Error Handling
Standard error format and common error codes for the WooCommerce Appointments REST API.
Error Response Format
All errors follow the standard WooCommerce REST API error format:
{
"code": "error_code",
"message": "Human-readable error message",
"data": {
"status": 400
}
}
HTTP Status Codes
| Status Code | Meaning | Common Causes |
|---|---|---|
200 | Success | Request completed successfully |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid parameters or validation failure |
401 | Unauthorized | Authentication required or invalid |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource doesn't exist |
500 | Internal Server Error | Server-side error |
Common Error Codes
Authentication Errors
rest_forbidden
- Status: 401
- Message: "Sorry, you are not allowed to do that."
- Cause: Missing or invalid authentication
woocommerce_rest_cannot_view
- Status: 401
- Message: "Sorry, you cannot view this resource."
- Cause: Authentication required but not provided
Permission Errors
woocommerce_rest_cannot_create
- Status: 403
- Message: "Sorry, you are not allowed to create resources."
- Cause: Missing
manage_woocommercecapability
woocommerce_rest_cannot_update
- Status: 403
- Message: "Sorry, you are not allowed to edit this resource."
- Cause: Missing
manage_woocommercecapability
woocommerce_rest_cannot_delete
- Status: 403
- Message: "Sorry, you are not allowed to delete this resource."
- Cause: Missing
manage_woocommercecapability
Validation Errors
woocommerce_appointments_invalid_status
- Status: 400
- Message: "Invalid appointment status."
- Cause: Invalid status value provided in create/update request
- Valid values:
unpaid,pending-confirmation,confirmed,paid,cancelled
woocommerce_rest_invalid_param
- Status: 400
- Message: "Invalid parameter(s):
{param_name}" - Cause: Invalid parameter value or type
woocommerce_rest_missing_callback_param
- Status: 400
- Message: "Missing parameter(s):
{param_name}" - Cause: Required parameter not provided
Resource Errors
woocommerce_rest_invalid_id
- Status: 404
- Message: "Invalid ID."
- Cause: Resource ID doesn't exist or is invalid
- Resolution: Verify the ID exists and is correct. Check that the resource hasn't been deleted.
rest_post_invalid_id
- Status: 404
- Message: "Invalid post ID."
- Cause: Appointment/product ID doesn't exist
- Resolution: Verify the appointment or product exists in the database. Check for typos in the ID.
woocommerce_rest_appointment_invalid_product_id
- Status: 400
- Message: "Invalid product ID."
- Cause: The product ID doesn't exist or isn't an appointable product
- Resolution: Ensure the product exists and has the "appointment" product type.
woocommerce_rest_appointment_invalid_staff_id
- Status: 400
- Message: "Invalid staff ID."
- Cause: Staff member doesn't exist or isn't assigned to the product
- Resolution: Verify the staff member exists and is assigned to the appointable product.
Availability Errors
woocommerce_appointments_invalid_date_range
- Status: 400
- Message: "Invalid date range."
- Cause: Start date is after end date, or dates are in the past
- Resolution: Ensure start_date is before end_date and both dates are in the future (unless editing existing appointment).
woocommerce_appointments_slot_not_available
- Status: 400
- Message: "The selected time slot is not available."
- Cause: The requested time slot conflicts with existing appointments or availability rules
- Resolution: Check availability using
/slotsendpoint before creating appointment. Verify no conflicts with other appointments or blocked time rules.
woocommerce_appointments_invalid_timezone
- Status: 400
- Message: "Invalid timezone."
- Cause: Timezone string is not valid
- Resolution: Use valid timezone identifiers (e.g., "America/New_York", "UTC"). See PHP timezone list.
Configuration Errors
rest_no_route
- Status: 404
- Message: "No route was found matching the URL and request method."
- Cause: Incorrect endpoint URL or HTTP method
- Resolution:
- Verify the endpoint URL is correct:
/wp-json/wc-appointments/v2/... - Check that permalinks are not set to "Plain" (Settings → Permalinks)
- Ensure you're using the correct HTTP method (GET, POST, PATCH, DELETE)
- Verify the API version (v1 or v2) exists
- Verify the endpoint URL is correct:
rest_cookie_invalid_nonce
- Status: 403
- Message: "Cookie nonce is invalid."
- Cause: Nonce expired or invalid when using cookie authentication
- Resolution: Regenerate the nonce. For admin pages, refresh the page to get a new nonce. Nonces expire after 24 hours.
woocommerce_rest_authentication_error
- Status: 401
- Message: "Invalid authentication details."
- Cause: Incorrect username/password or API key/secret
- Resolution:
- Verify username and application password are correct
- Check that API keys haven't been revoked
- Ensure no extra spaces in credentials
- For application passwords, you can use with or without spaces
Data Validation Errors
woocommerce_rest_missing_callback_param
- Status: 400
- Message: "Missing parameter(s):
{param_name}" - Cause: Required parameter not provided in request
- Resolution: Check the endpoint documentation for required parameters. Common required fields:
product_id- Required for creating appointmentsstart_date- Required for appointmentsend_date- Required for appointments
woocommerce_rest_invalid_param
- Status: 400
- Message: "Invalid parameter(s):
{param_name}" - Cause: Parameter value is invalid or wrong type
- Resolution:
- Verify parameter types (string, integer, boolean, etc.)
- Check date formats:
YYYY-MM-DD HH:MM:SS(e.g., "2025-12-25 10:00:00") - Ensure numeric IDs are integers, not strings
- Validate enum values (status must be one of: unpaid, pending-confirmation, confirmed, paid, cancelled, completed)
woocommerce_rest_invalid_date
- Status: 400
- Message: "Invalid date format."
- Cause: Date string doesn't match expected format
- Resolution: Use format
YYYY-MM-DD HH:MM:SS(e.g., "2025-12-25 10:00:00"). Ensure dates are in the site's timezone or include timezone offset.
Server Errors
rest_cannot_connect
- Status: 500
- Message: "Error connecting to the API."
- Cause: Server configuration issue or plugin conflict
- Resolution:
- Check WordPress and WooCommerce are active
- Verify WooCommerce Appointments plugin is active
- Check for plugin conflicts
- Review server error logs
- Ensure REST API is enabled (not disabled in wp-config.php)
rest_invalid_json
- Status: 400
- Message: "Invalid JSON in request body."
- Cause: Malformed JSON in POST/PATCH request
- Resolution:
- Validate JSON syntax using a JSON validator
- Ensure Content-Type header is
application/json - Check for unescaped quotes or special characters
- Verify all brackets and braces are properly closed
woocommerce_rest_database_error
- Status: 500
- Message: "Database error occurred."
- Cause: Database connection issue or query failure
- Resolution:
- Check database connection
- Review database error logs
- Verify database tables exist
- Check for database permission issues
Error Handling Examples
JavaScript
async function handleApiRequest(url, options = {}) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (error.code) {
case 'rest_forbidden':
case 'woocommerce_rest_cannot_view':
console.error('Authentication required');
break;
case 'woocommerce_rest_cannot_create':
case 'woocommerce_rest_cannot_update':
case 'woocommerce_rest_cannot_delete':
console.error('Insufficient permissions');
break;
case 'woocommerce_appointments_invalid_status':
console.error('Invalid status:', error.message);
break;
default:
console.error('API Error:', error.message);
}
throw error;
}
return await response.json();
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
PHP
function handle_api_response($response) {
if (is_wp_error($response)) {
return [
'success' => false,
'error' => $response->get_error_message()
];
}
$status_code = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if ($status_code >= 400) {
$error_code = $data['code'] ?? 'unknown_error';
$error_message = $data['message'] ?? 'An error occurred';
return [
'success' => false,
'error_code' => $error_code,
'error_message' => $error_message,
'status_code' => $status_code
];
}
return [
'success' => true,
'data' => $data
];
}
Common Error Scenarios & Solutions
Scenario 1: "401 Unauthorized" when using Application Password
Problem: Getting 401 even with correct credentials.
Solutions:
-
Check Application Password format:
- Application passwords are 24 characters
- Can include spaces:
xxxx xxxx xxxx xxxx xxxx xxxx - Can be used without spaces:
xxxxxxxxxxxxxxxxxxxxxxxx - Ensure no extra characters or line breaks
-
Verify username:
- Use your WordPress username (not email)
- Check for typos or case sensitivity
-
Check Application Password is active:
- Go to Users → Profile
- Verify the application password hasn't been revoked
- Create a new one if needed
-
Test with cURL:
curl -u username:app_password \
"https://your-site.com/wp-json/wc-appointments/v2/appointments"
Scenario 2: "404 No route was found" - Routes Not Registered
Problem: Endpoint returns 404 and routes don't appear in route list (e.g., rest_get_server()->get_routes() shows no wc-appointments routes).
This is different from a simple 404 - if routes aren't registered at all, the plugin's REST API isn't initializing.
Solutions:
-
Verify plugin is active:
// Check if plugin is active
if ( ! class_exists( 'WC_Appointments' ) ) {
// Plugin not loaded
} -
Check permalink settings (CRITICAL):
- Go to Settings → Permalinks
- MUST NOT be set to "Plain"
- Choose any other option (Post name, Day and name, Month and name, etc.)
- Click "Save Changes" (even if no changes made)
- This is required for REST API routes to register
-
Flush rewrite rules:
// In functions.php or via WP-CLI
flush_rewrite_rules();Or:
- Deactivate WooCommerce Appointments plugin
- Reactivate it
- This forces rewrite rules to regenerate
-
Verify REST API class loads:
// Debug: Check if REST API class exists
if ( class_exists( 'WC_Appointments_REST_API' ) ) {
$rest_api = new WC_Appointments_REST_API();
// Routes should register on rest_api_init hook
} else {
// Plugin file not loaded - check includes
} -
Check for REST API blocking:
- Verify REST API isn't disabled in
wp-config.php - Remove any code that blocks
/wp-json/requests - Check
.htaccessfor rules blocking/wp-json/ - Verify security plugins aren't blocking REST API
- Verify REST API isn't disabled in
-
Test REST API availability:
// Check if WordPress REST API is available
if ( ! function_exists( 'rest_url' ) ) {
// REST API disabled or not available
}
// Test basic REST API
$test = wp_remote_get( site_url( '/wp-json/' ) );
if ( is_wp_error( $test ) ) {
// REST API not accessible
} -
Check hook firing:
// Add debug to see if rest_api_init fires
add_action( 'rest_api_init', function() {
error_log( 'REST API init fired' );
if ( class_exists( 'WC_Appointments_REST_API' ) ) {
error_log( 'WC_Appointments_REST_API class exists' );
}
}, 5 ); -
Verify plugin file inclusion:
- Check that
includes/class-wc-appointments-rest-api.phpis being included - File should be included in
woocommerce-appointments.phparound line 369 - Verify no fatal errors preventing file from loading
- Check that
Quick Diagnostic Script:
// Add this temporarily to diagnose the issue
add_action( 'init', function() {
if ( ! is_admin() ) return;
echo '<h2>REST API Diagnostic</h2>';
// Check plugin
echo '<p>Plugin Active: ' . ( class_exists( 'WC_Appointments' ) ? 'YES' : 'NO' ) . '</p>';
// Check REST API class
echo '<p>REST API Class: ' . ( class_exists( 'WC_Appointments_REST_API' ) ? 'YES' : 'NO' ) . '</p>';
// Check permalinks
$permalink_structure = get_option( 'permalink_structure' );
echo '<p>Permalink Structure: ' . ( $permalink_structure ? $permalink_structure : 'PLAIN (PROBLEM!)' ) . '</p>';
// Check REST API available
echo '<p>REST API Functions: ' . ( function_exists( 'rest_url' ) ? 'YES' : 'NO' ) . '</p>';
// List routes
global $wp_rest_server;
$wp_rest_server = rest_get_server();
$routes = $wp_rest_server->get_routes();
$appointment_routes = array_filter( array_keys( $routes ), function( $route ) {
return strpos( $route, 'wc-appointments' ) !== false;
} );
echo '<p>Appointment Routes Found: ' . count( $appointment_routes ) . '</p>';
if ( empty( $appointment_routes ) ) {
echo '<p style="color:red;"><strong>No routes found! Check permalinks and flush rewrite rules.</strong></p>';
} else {
echo '<pre>' . print_r( $appointment_routes, true ) . '</pre>';
}
}, 999 );
Scenario 3: "400 Invalid date range" when creating appointment
Problem: Appointment creation fails with date validation error.
Solutions:
-
Check date format:
- Required format:
YYYY-MM-DD HH:MM:SS - Example:
"2025-12-25 10:00:00" - Include leading zeros:
"2025-01-05 09:00:00"(not"2025-1-5 9:0:0")
- Required format:
-
Verify date order:
start_datemust be beforeend_date- Check for timezone issues
-
Ensure future dates:
- For new appointments, dates must be in the future
- Unless editing existing appointment
-
Example correct payload:
{
"product_id": 123,
"start_date": "2025-12-25 10:00:00",
"end_date": "2025-12-25 11:00:00"
}
Scenario 4: "400 Slot not available" error
Problem: Can't create appointment because slot is unavailable.
Solutions:
-
Check availability first:
curl "https://your-site.com/wp-json/wc-appointments/v2/slots?product_ids=123&min_date=2025-12-25&max_date=2025-12-25" -
Verify no conflicts:
- Check for existing appointments at that time
- Verify availability rules aren't blocking the time
- Check staff availability if staff is assigned
-
Check capacity:
- Verify product inventory/capacity allows more bookings
- Check if staff capacity is reached
-
Use available slot:
- Query
/slotsendpoint to find available times - Use a slot marked as
available: true
- Query
Scenario 5: "403 Forbidden" when user has correct role
Problem: User has admin role but still gets 403.
Solutions:
-
Check capabilities:
- Required:
manage_woocommercecapability - Verify user role includes this capability
- Check if custom role has been modified
- Required:
-
Verify API key permissions:
- For WooCommerce API keys, check read/write permissions
- Regenerate keys if needed
-
Test with different user:
- Try with a different admin account
- Verify the issue is user-specific or global
Scenario 6: CORS errors in browser
Problem: Browser blocks API requests with CORS errors.
Solutions:
-
Server-side solution (recommended):
- Add CORS headers in
.htaccessor server config - Or use a plugin like "CORS Headers"
- Add CORS headers in
-
For development:
- Use a browser extension to disable CORS (not for production)
- Or use server-to-server requests instead
-
Check request origin:
- Ensure requests are from allowed domains
- Verify
Access-Control-Allow-Originheader is set
Best Practices
- Always check response status - Don't assume success
- Handle specific error codes - Provide user-friendly messages
- Log errors - For debugging and monitoring
- Retry on network errors - With exponential backoff
- Validate input client-side - Prevent unnecessary API calls
- Show user-friendly messages - Don't expose technical error details
- Test authentication first - Verify credentials before making complex requests
- Check availability before booking - Query
/slotsendpoint first - Handle rate limiting - Implement retry logic with backoff
- Monitor error patterns - Track common errors to identify issues
Related Documentation
- Authentication - Setting up authentication
- Appointments Endpoints - Appointment validation rules
- Examples - Error handling in code examples