Skip to main content

Authentication & Permissions

Authentication Methods

The WooCommerce Appointments REST API supports multiple authentication methods. Choose the one that best fits your use case.

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

  1. Go to Users → Profile (or Users → Your Profile)
  2. Scroll down to the Application Passwords section
  3. Enter a name for the application (e.g., "Postman", "My App")
  4. Click Add New Application Password
  5. Copy the password immediately - it's only shown once!

Add Application Password

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.

Generate API keys in WooCommerce → Settings → Advanced → REST API.

REST API keys

Generate API key

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: _wpnonce or X-WP-Nonce header
  • 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

  1. Use HTTPS - Always use SSL/TLS for API requests
  2. Protect API Keys - Never expose consumer secrets in client-side code
  3. Rotate Keys - Regularly rotate API keys for security
  4. Limit Permissions - Use read-only keys when possible
  5. Validate Input - Always validate and sanitize input data
  6. Rate Limiting - Implement rate limiting in your application

Postman

Postman is a popular API testing tool. Here's how to set it up:

Step 1: Create a New Request

  1. Open Postman
  2. Click NewHTTP Request
  3. Set the method (GET, POST, etc.)
  4. Enter the endpoint URL: https://your-site.com/wp-json/wc-appointments/v2/appointments

Step 2: Configure Authentication

Option A: Application Password (Recommended)

  1. Click the Authorization tab
  2. Select Basic Auth from the Type dropdown
  3. Enter your WordPress Username
  4. Enter your Application Password (from Users → Profile)
  5. Click Send

Option B: WooCommerce API Keys

  1. Click the Authorization tab
  2. Select Basic Auth from the Type dropdown
  3. Enter your Consumer Key as Username
  4. Enter your Consumer Secret as Password
  5. Click Send

Step 3: List All Available Routes

To see all available REST API routes (useful for debugging):

  1. Create a new GET request
  2. Set URL to: https://your-site.com/wp-json/
  3. Click Send
  4. 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)

  1. Click Save
  2. Create a new collection (e.g., "WooCommerce Appointments API")
  3. Save the request for future use

Postman Environment Variables

Create an environment for easy switching:

  1. Click the gear icon (⚙️) → Manage Environments
  2. Click Add
  3. Add variables:
    • base_url: https://your-site.com
    • username: Your WordPress username
    • app_password: Your application password
  4. In your request, use: {{base_url}}/wp-json/wc-appointments/v2/appointments
  5. In Authorization, use: {{username}} and {{app_password}}

Insomnia

Insomnia is another popular REST client:

Setup with Application Password

  1. Create a new request
  2. Set the URL: https://your-site.com/wp-json/wc-appointments/v2/appointments
  3. Click the Auth tab
  4. Select Basic Auth
  5. Enter:
    • Username: Your WordPress username
    • Password: Your application password
  6. Click Send

Environment Setup

  1. Click Manage Environments (bottom left)
  2. Create a new environment
  3. Add variables:
    {
    "base_url": "https://your-site.com",
    "username": "your-username",
    "app_password": "xxxx xxxx xxxx xxxx xxxx xxxx"
    }
  4. 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:

  1. Create a new GET request
  2. Set URL to: https://your-site.com/wp-json/
  3. No authentication needed (this is a public endpoint)
  4. 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

  1. 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
  2. Plugin Not Fully Loaded

    • Check: Verify WC_Appointments_REST_API class exists
    if ( ! class_exists( 'WC_Appointments_REST_API' ) ) {
    // Plugin REST API not loaded
    }
  3. REST API Disabled

    • Check: Verify REST API functions exist
    if ( ! function_exists( 'rest_url' ) ) {
    // REST API disabled
    }
    • Solution: Remove any code in wp-config.php that disables REST API
  4. Rewrite Rules Not Flushed

    • Solution:
      • Deactivate and reactivate WooCommerce Appointments
      • Or run: flush_rewrite_rules() via code or WP-CLI

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.