Authentication & Permissions
Authentication Methods
The WooCommerce Appointments REST API supports multiple authentication methods. Choose the one that best fits your use case.
1. Application Passwords (Recommended for Testing & Development)
Application Passwords are the easiest way to authenticate with the REST API. They're generated from your WordPress user profile and work immediately without additional configuration.
Generate Application Password
- Go to Users → Profile (or Users → Your Profile)
- Scroll down to the Application Passwords section
- Enter a name for the application (e.g., "Postman", "My App")
- Click Add New Application Password
- Copy the password immediately - it's only shown once!

Important: The password format is xxxx xxxx xxxx xxxx xxxx xxxx (24 characters with spaces). You can use it with or without spaces.
Usage
Application Passwords use HTTP Basic Authentication:
- Username: Your WordPress username
- Password: The generated application password
Example with cURL:
curl -u username:xxxx\ xxxx\ xxxx\ xxxx\ xxxx\ xxxx \
"https://example.com/wp-json/wc-appointments/v2/appointments"
Example with Password (no spaces):
curl -u username:xxxxxxxxxxxxxxxxxxxxxxxx \
"https://example.com/wp-json/wc-appointments/v2/appointments"
Advantages:
- ✅ Quick setup - no WooCommerce configuration needed
- ✅ Easy to revoke - delete from user profile
- ✅ Works with all REST API endpoints
- ✅ Perfect for testing with Postman, Insomnia, etc.
2. WooCommerce API Keys (Recommended for Production)
Generate API keys in WooCommerce → Settings → Advanced → REST API.


Usage:
- Consumer Key: Username
- Consumer Secret: Password
- Use HTTP Basic Authentication or query parameters
Example with cURL (Basic Auth):
curl -u consumer_key:consumer_secret \
"https://example.com/wp-json/wc-appointments/v2/appointments"
Example with Query Parameters:
curl "https://example.com/wp-json/wc-appointments/v2/appointments?consumer_key=ck_xxx&consumer_secret=cs_xxx"
Advantages:
- ✅ Granular permissions (read/write)
- ✅ Better for production integrations
- ✅ Can be scoped to specific users
2. OAuth 1.0a
For third-party applications that need user authorization.
Documentation: See WooCommerce REST API OAuth Documentation
3. Cookie/Nonce (For Logged-in Users)
For WordPress admin pages and frontend AJAX requests.
Usage:
- Include WordPress nonce in request
- Nonce parameter:
_wpnonceorX-WP-Nonceheader - Requires valid WordPress session cookie
Example:
fetch('/wp-json/wc-appointments/v1/appointments', {
headers: {
'X-WP-Nonce': wpApiSettings.nonce
}
})
Permissions
Public Read Endpoints
These endpoints are publicly accessible (no authentication required):
- Slots (V1/V2):
GET /wc-appointments/v1/slots,GET /wc-appointments/v2/slots - Index (V2):
GET /wc-appointments/v2/index - Availabilities (V1/V2):
GET /wc-appointments/v1/availabilities,GET /wc-appointments/v2/availabilities - Products (Published):
GET /wc-appointments/v1/products,GET /wc-appointments/v1/products/{id} - Product Categories (Published):
GET /wc-appointments/v1/products/categories,GET /wc-appointments/v1/products/categories/{id}
Note: Non-readable products are automatically filtered out using WooCommerce post permission checks.
Authentication Required
These endpoints require authentication:
- Appointments CRUD (V1/V2): All appointment endpoints
- Availability CRUD (V2): Create, update, delete availability rules
- Staff:
GET /wc-appointments/v1/staff,GET /wc-appointments/v1/staff/{id}
Capability Required
These operations require the manage_woocommerce capability:
- Create Appointments:
POST /wc-appointments/v1/appointments - Update Appointments:
PUT/PATCH /wc-appointments/v1/appointments/{id} - Delete Appointments:
DELETE /wc-appointments/v1/appointments/{id} - Create Availabilities:
POST /wc-appointments/v2/availabilities - Update Availabilities:
PUT/PATCH /wc-appointments/v2/availabilities/{id} - Delete Availabilities:
DELETE /wc-appointments/v2/availabilities/{id} - Batch Operations:
POST /wc-appointments/v1/appointments/batch
Permission Filters
Controllers use internal permission filters:
- Published posts are readable by non-store owners
- Private/unpublished items remain restricted
- Standard WooCommerce permission checks apply
Error Responses
401 Unauthorized
Returned when authentication is required but not provided or invalid.
{
"code": "woocommerce_rest_cannot_view",
"message": "Sorry, you cannot view this resource.",
"data": {
"status": 401
}
}
403 Forbidden
Returned when the user lacks required capabilities.
{
"code": "woocommerce_rest_cannot_create",
"message": "Sorry, you are not allowed to create resources.",
"data": {
"status": 403
}
}
Security Best Practices
- Use HTTPS - Always use SSL/TLS for API requests
- Protect API Keys - Never expose consumer secrets in client-side code
- Rotate Keys - Regularly rotate API keys for security
- Limit Permissions - Use read-only keys when possible
- Validate Input - Always validate and sanitize input data
- Rate Limiting - Implement rate limiting in your application
Setting Up Popular API Clients
Postman
Postman is a popular API testing tool. Here's how to set it up:
Step 1: Create a New Request
- Open Postman
- Click New → HTTP Request
- Set the method (GET, POST, etc.)
- Enter the endpoint URL:
https://your-site.com/wp-json/wc-appointments/v2/appointments
Step 2: Configure Authentication
Option A: Application Password (Recommended)
- Click the Authorization tab
- Select Basic Auth from the Type dropdown
- Enter your WordPress Username
- Enter your Application Password (from Users → Profile)
- Click Send
Option B: WooCommerce API Keys
- Click the Authorization tab
- Select Basic Auth from the Type dropdown
- Enter your Consumer Key as Username
- Enter your Consumer Secret as Password
- Click Send
Step 3: List All Available Routes
To see all available REST API routes (useful for debugging):
- Create a new GET request
- Set URL to:
https://your-site.com/wp-json/ - Click Send
- The response shows all registered routes, including WooCommerce Appointments routes
Example Response:
{
"name": "WordPress Site",
"description": "...",
"url": "https://your-site.com",
"home": "https://your-site.com",
"namespaces": [
"oembed/1.0",
"wp/v2",
"wc/v3",
"wc-appointments/v1",
"wc-appointments/v2"
],
"authentication": {
"applicationpasswords": {...},
"oauth1": {...}
},
"routes": {
"/wp/v2": {...},
"/wc/v3": {...},
"/wc-appointments/v1/appointments": {...},
"/wc-appointments/v2/appointments": {...},
...
}
}
To filter for appointment routes only:
- Look for routes starting with
/wc-appointments/in the response - Or use:
https://your-site.com/wp-json/wc-appointments/v2/to see v2 routes - Or use:
https://your-site.com/wp-json/wc-appointments/v1/to see v1 routes
Step 4: Save as Collection (Optional)
- Click Save
- Create a new collection (e.g., "WooCommerce Appointments API")
- Save the request for future use
Postman Environment Variables
Create an environment for easy switching:
- Click the gear icon (⚙️) → Manage Environments
- Click Add
- Add variables:
base_url:https://your-site.comusername: Your WordPress usernameapp_password: Your application password
- In your request, use:
{{base_url}}/wp-json/wc-appointments/v2/appointments - In Authorization, use:
{{username}}and{{app_password}}
Insomnia
Insomnia is another popular REST client:
Setup with Application Password
- Create a new request
- Set the URL:
https://your-site.com/wp-json/wc-appointments/v2/appointments - Click the Auth tab
- Select Basic Auth
- Enter:
- Username: Your WordPress username
- Password: Your application password
- Click Send
Environment Setup
- Click Manage Environments (bottom left)
- Create a new environment
- Add variables:
{
"base_url": "https://your-site.com",
"username": "your-username",
"app_password": "xxxx xxxx xxxx xxxx xxxx xxxx"
} - Use variables in requests:
{{ base_url }}/wp-json/wc-appointments/v2/appointments
HTTPie
HTTPie is a command-line HTTP client:
Basic Usage
# With Application Password
http -a username:app_password \
GET https://example.com/wp-json/wc-appointments/v2/appointments
# With WooCommerce API Keys
http -a consumer_key:consumer_secret \
GET https://example.com/wp-json/wc-appointments/v2/appointments
POST Request Example
http -a username:app_password \
POST https://example.com/wp-json/wc-appointments/v2/appointments \
product_id:=123 \
start_date="2025-12-25 10:00:00" \
end_date="2025-12-25 11:00:00" \
status="confirmed"
cURL
Basic GET Request
# With Application Password
curl -u username:app_password \
"https://example.com/wp-json/wc-appointments/v2/appointments"
# With WooCommerce API Keys
curl -u consumer_key:consumer_secret \
"https://example.com/wp-json/wc-appointments/v2/appointments"
POST Request Example
curl -u username:app_password \
-X POST \
-H "Content-Type: application/json" \
-d '{
"product_id": 123,
"start_date": "2025-12-25 10:00:00",
"end_date": "2025-12-25 11:00:00",
"status": "confirmed"
}' \
"https://example.com/wp-json/wc-appointments/v2/appointments"
JavaScript (Fetch API)
With Application Password
// Base64 encode username:password
const credentials = btoa('username:app_password');
fetch('https://example.com/wp-json/wc-appointments/v2/appointments', {
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
With WooCommerce API Keys
const credentials = btoa('consumer_key:consumer_secret');
fetch('https://example.com/wp-json/wc-appointments/v2/appointments', {
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data));
Python (requests library)
import requests
from requests.auth import HTTPBasicAuth
# With Application Password
response = requests.get(
'https://example.com/wp-json/wc-appointments/v2/appointments',
auth=HTTPBasicAuth('username', 'app_password')
)
print(response.json())
# POST Request
data = {
'product_id': 123,
'start_date': '2025-12-25 10:00:00',
'end_date': '2025-12-25 11:00:00',
'status': 'confirmed'
}
response = requests.post(
'https://example.com/wp-json/wc-appointments/v2/appointments',
auth=HTTPBasicAuth('username', 'app_password'),
json=data
)
print(response.json())
PHP (wp_remote_request)
// With Application Password
$username = 'your-username';
$password = 'your-app-password';
$url = 'https://example.com/wp-json/wc-appointments/v2/appointments';
$response = wp_remote_request($url, [
'headers' => [
'Authorization' => 'Basic ' . base64_encode($username . ':' . $password),
'Content-Type' => 'application/json',
],
]);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
Testing Authentication
Quick Test
Test your authentication with a simple GET request:
# Test with Application Password
curl -u username:app_password \
"https://your-site.com/wp-json/wc-appointments/v2/appointments"
# Test with WooCommerce API Keys
curl -u consumer_key:consumer_secret \
"https://your-site.com/wp-json/wc-appointments/v2/appointments"
Verify Authentication Works
A successful authenticated request returns appointment data:
[
{
"id": 123,
"product_id": 456,
"start_date": "2025-12-25 10:00:00",
...
}
]
An authentication failure returns:
{
"code": "rest_forbidden",
"message": "Sorry, you are not allowed to do that.",
"data": {
"status": 401
}
}
Discovering Available Routes
Get All Routes via Postman
To see all available REST API routes in Postman:
- Create a new GET request
- Set URL to:
https://your-site.com/wp-json/ - No authentication needed (this is a public endpoint)
- Click Send
The response includes all registered routes. Look for routes under:
/wc-appointments/v1/- Version 1 endpoints/wc-appointments/v2/- Version 2 endpoints
Filtered View:
- V2 Routes:
https://your-site.com/wp-json/wc-appointments/v2/ - V1 Routes:
https://your-site.com/wp-json/wc-appointments/v1/
These endpoints show only the routes for that namespace.
Get Routes via cURL
# Get all routes
curl "https://your-site.com/wp-json/"
# Get only WooCommerce Appointments v2 routes
curl "https://your-site.com/wp-json/wc-appointments/v2/"
# Get only WooCommerce Appointments v1 routes
curl "https://your-site.com/wp-json/wc-appointments/v1/"
Get Routes via JavaScript
// Get all routes
fetch('https://your-site.com/wp-json/')
.then(response => response.json())
.then(data => {
// Filter for appointment routes
const appointmentRoutes = Object.keys(data.routes).filter(route =>
route.includes('wc-appointments')
);
console.log('Appointment routes:', appointmentRoutes);
});
Troubleshooting: Routes Not Found (404)
If you're getting a 404 error and routes don't appear when listing REST API routes, this usually means the routes aren't being registered.
Common Causes & Solutions
-
Permalinks set to "Plain" (Most Common)
- Problem: Routes cannot register with "Plain" permalinks
- Solution:
- Go to Settings → Permalinks
- Choose any option EXCEPT "Plain"
- Click Save Changes
- Deactivate and reactivate WooCommerce Appointments plugin
-
Plugin Not Fully Loaded
- Check: Verify
WC_Appointments_REST_APIclass exists
if ( ! class_exists( 'WC_Appointments_REST_API' ) ) {
// Plugin REST API not loaded
} - Check: Verify
-
REST API Disabled
- Check: Verify REST API functions exist
if ( ! function_exists( 'rest_url' ) ) {
// REST API disabled
}- Solution: Remove any code in
wp-config.phpthat disables REST API
-
Rewrite Rules Not Flushed
- Solution:
- Deactivate and reactivate WooCommerce Appointments
- Or run:
flush_rewrite_rules()via code or WP-CLI
- Solution:
Diagnostic Code
Add this temporarily to check what's happening:
add_action( 'init', function() {
if ( ! current_user_can( 'manage_options' ) ) return;
// Check if routes are registered
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;
} );
if ( empty( $appointment_routes ) ) {
// Routes not registered - check permalinks!
error_log( 'WooCommerce Appointments REST API routes not found. Check permalink settings.' );
}
}, 999 );
See Error Handling - Routes Not Registered for detailed troubleshooting.