Skip to main content
All Partner API errors return a consistent JSON envelope with a machine-readable code field. Build your error handling logic around the code, not the message.

Error Envelope

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": { ... },
    "requestId": "a1b2c3d4-..."
  }
}

Complete Error Reference

Authentication & Authorization Errors

HTTP StatusCodeCauseHow to Fix
401UNAUTHORIZEDAPI key is missing, invalid, expired, or the associated partner account is suspendedVerify your x-api-key header is set correctly; contact support if the key is valid but still rejected
403FORBIDDENValid API key but missing the required permission for this endpointRequest the missing permission from the CleanLife team
403INVALID_PARTNER_DOMAINThe Origin or Referer header on your request does not match any registered domain for this partnerRegister your domain with CleanLife or remove the Origin header for server-to-server calls
403SANDBOX_DOMAIN_NOT_ALLOWEDYour request came from a domain registered as a sandbox domain; sandbox access is currently disabledContact CleanLife to register a production domain

Validation Errors

HTTP StatusCodeCauseHow to Fix
400VALIDATION_ERROROne or more request fields failed validation (wrong type, missing required field, out-of-range value, invalid UUID, etc.)Read the details field for a breakdown of which fields failed and why
Example — Missing required field:
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "serviceId must be a UUID",
    "details": {
      "message": ["serviceId must be a UUID"],
      "statusCode": 400,
      "error": "Bad Request"
    },
    "requestId": "..."
  }
}
Common validation failures:
FieldValidation RuleError
serviceIdMust be a valid UUID v4; requiredserviceId must be a UUID
contactIdMust be a valid UUID v4contactId must be a UUID
phoneMust be a valid Saudi phone numberphone must be a valid phone number
dateMust be an ISO 8601 date stringdate must be a valid ISO 8601 date string
timeslot.startAtMust be a stringtimeslot.startAt must be a string
hoursMust be integer ≥ 1hours must not be less than 1
limit (pagination)Must be integer 1–100limit must not be greater than 100
couponIdsMax 2 itemscouponIds must contain no more than 2 elements

Resource Errors

HTTP StatusCodeCauseHow to Fix
404RESOURCE_NOT_FOUNDBooking, contact, service, webhook subscription, or delivery not found — either does not exist or belongs to a different partnerVerify the ID and that the resource was created by your partner account
404SERVICE_NOT_ALLOWEDThe serviceId is not enabled for your partner accountUse a serviceId from GET /partners/services

Booking Business Rule Errors

HTTP StatusCodeCauseHow to Fix
409DUPLICATE_EXTERNAL_REFERENCEYou attempted to create or update a booking with an externalReference that already exists for your partner accountUse a unique externalReference value per booking
422BOOKING_CREATION_FAILEDThe booking could not be completed — typically a payment or validation failureReview your booking request fields; retry once; if persistent, contact support
422BOOKING_NOT_EDITABLEAttempted to update a booking that is not in in progress or waiting payment statusOnly bookings in these two statuses can be rescheduled or have their externalReference updated
422BOOKING_APPOINTMENT_NOT_FOUNDAttempted to reschedule a booking that has no associated service appointmentThis is an unexpected state; contact support
422BOOKING_ALREADY_CANCELLEDAttempted to cancel a booking that is already cancelledNo action needed; the booking is already cancelled
422BOOKING_NOT_PAYABLEAttempted to confirm payment for a cancelled or failed bookingPayment can only be confirmed for active bookings
422PAYMENT_RESPONSIBILITY_MISMATCHAttempted to call confirm-payment but your partner account has paymentResponsibility = CLEANOSOnly PARTNER responsibility accounts can confirm payments
422PAYMENT_ALREADY_CONFIRMEDAttempted to confirm payment for a booking whose payment was already confirmedPayment confirmation is idempotent in intent but rejected as a duplicate; no action needed

Webhook Errors

HTTP StatusCodeCauseHow to Fix
400VALIDATION_ERROR (message: “Webhook URL must use HTTPS”)Webhook subscription URL uses HTTP when HTTPS is enforcedUse an HTTPS URL
400VALIDATION_ERROR (message: “Webhook URL host is not allowed”)Webhook URL points to a blocked host (localhost, 127.x.x.x, 10.x.x.x, 192.168.x.x, etc.)Use a publicly routable HTTPS URL
400VALIDATION_ERROR (message: “Partner has no allowed webhook domains configured”)Your partner account has no allowed domains registered, so no webhook URL can be validatedContact CleanLife to register your webhook domain
400VALIDATION_ERROR (message: “Webhook domain is not allowed for this partner”)The hostname of the webhook URL is not in your allowed domains listRegister the domain with CleanLife or use a URL from an already-allowed domain
404RESOURCE_NOT_FOUNDWebhook subscription not foundVerify the subscription ID
404DELIVERY_NOT_RETRYABLEAttempted to retry a delivery that is not in FAILED statusOnly FAILED deliveries can be manually retried

Rate Limit Errors

HTTP StatusCodeCauseHow to Fix
429RATE_LIMIT_EXCEEDEDExceeded your API key’s request limit within the current 60-second sliding windowWait for the window to reset and retry; implement exponential backoff

Server Errors

HTTP StatusCodeCauseHow to Fix
500INTERNAL_ERRORUnexpected server-side errorRetry with exponential backoff; if persistent, contact support with the requestId from the response

Using requestId for Support

Every response (including errors) includes a requestId in the error envelope and an X-Request-Id response header. If you contact CleanLife support about an unexpected error, always include this value — it allows the engineering team to trace the exact request through server logs.
# See the request ID in the response header
curl -i -X GET "https://apiv3.thecleanlife.dev/v1/partners/services" \
  -H "x-api-key: YOUR_KEY"
# → X-Request-Id: a1b2c3d4-0000-0000-0000-000000000001

Retry Strategy

Error CodeRetryable?Notes
VALIDATION_ERRORNoFix the request payload before retrying
UNAUTHORIZEDNoFix the API key before retrying
FORBIDDENNoRequest the missing permission
RESOURCE_NOT_FOUNDNoThe resource does not exist
DUPLICATE_EXTERNAL_REFERENCENoUse a different externalReference
BOOKING_CREATION_FAILEDYesRetry once with the same or corrected payload
RATE_LIMIT_EXCEEDEDYesBack off and retry after the 60-second window
INTERNAL_ERRORYesRetry with exponential backoff (see Best Practices)