This tutorial was written by Claude Code (an AI) and has not yet been reviewed. Follow along with caution. If the tutorial was helpful or a specific part was not clear/correct, please provide feedback at the bottom of the page. Thank you.
This guide covers CoCart Preview API features. The checkout endpoints require CoCart v4.6 and up with the Preview API enabled.
Overview
The CoCart Checkout API provides a complete solution for processing e-commerce transactions through three main endpoints:
GET /checkout - Retrieve checkout data including cart contents, totals, and available payment/shipping methods
POST /checkout - Update checkout information such as billing address, shipping address, and payment method
PUT /checkout - Process the final checkout and create the order
Prerequisites
Before implementing the checkout flow, ensure you have:
A valid cart with items added
Proper authentication (Cart Key, Basic Auth, or JWT)
Required customer information (billing address at minimum)
Available payment and shipping methods configured in WooCommerce
Basic Checkout Flow
Get Checkout Data
Retrieve current checkout information to display available options
Update Checkout Information
Set billing/shipping addresses and selected payment/shipping methods
Process Checkout
Complete the transaction and create the order
Authentication
The CoCart Checkout API uses WooCommerce consumer key/secret authentication for secure access:
Authentication Methods
Consumer Key/Secret : Required for all API access (see Consumer Key Setup )
Cart Key : Identifies the customer’s cart session and automatically provides customer context for registered users
Request Structure
// All requests require consumer authentication
const url = `/wp-json/cocart/preview/checkout?consumer_key=ck_123&consumer_secret=cs_456` ;
// Cart key identifies the specific cart and customer (if logged in)
const headers = {
'Cart-Key' : 'your-cart-key-here' , // Contains customer context automatically
'Content-Type' : 'application/json'
};
The cart key automatically contains customer context for registered users. No separate customer ID parameter is needed since WooCommerce sessions already track the user ID.
API Endpoints
Get Checkout Data
Retrieve current checkout information including cart contents, totals, addresses, and available shipping/payment methods.
curl -X GET "https://yoursite.com/wp-json/cocart/preview/checkout?consumer_key=ck_1234567890abcdef&consumer_secret=cs_1234567890abcdef" \
-H "Cart-Key: your-cart-key-here" \
-H "Content-Type: application/json"
$cart_key = 'your-cart-key-here' ;
$consumer_key = 'ck_1234567890abcdef' ;
$consumer_secret = 'cs_1234567890abcdef' ;
$url = add_query_arg ( array (
'consumer_key' => $consumer_key ,
'consumer_secret' => $consumer_secret
), 'https://yoursite.com/wp-json/cocart/preview/checkout' );
$response = wp_remote_get ( $url , array (
'headers' => array (
'Cart-Key' => $cart_key ,
'Content-Type' => 'application/json' ,
),
'timeout' => 30 ,
) );
if ( ! is_wp_error ( $response ) ) {
$checkout_data = json_decode ( wp_remote_retrieve_body ( $response ), true );
// Access cart contents
$cart_items = $checkout_data [ 'cart_contents' ];
$cart_totals = $checkout_data [ 'cart_totals' ];
$shipping_methods = $checkout_data [ 'shipping_methods' ];
// Customer data available if cart belongs to registered user
if ( isset ( $checkout_data [ 'customer_data' ] ) ) {
$customer_data = $checkout_data [ 'customer_data' ];
}
}
Guest Checkout (Fetch API)
Registered Customer (Async/Await)
const cartKey = 'your-cart-key-here' ;
const consumerKey = 'ck_1234567890abcdef' ;
const consumerSecret = 'cs_1234567890abcdef' ;
const url = new URL ( 'https://yoursite.com/wp-json/cocart/preview/checkout' );
url . searchParams . append ( 'consumer_key' , consumerKey );
url . searchParams . append ( 'consumer_secret' , consumerSecret );
fetch ( url . toString (), {
method: 'GET' ,
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
},
})
. then ( response => response . json ())
. then ( data => {
console . log ( 'Checkout data:' , data );
// Display cart items
Object . values ( data . cart_contents ). forEach ( item => {
console . log ( ` ${ item . product_name } - Qty: ${ item . quantity } ` );
});
// Display total
console . log ( `Total: ${ data . cart_totals . total } ` );
})
. catch ( error => {
console . error ( 'Error:' , error );
});
Update checkout details such as billing address, shipping address, payment method, or shipping method.
Update Billing Address
Update Shipping and Payment Method
Complete Address Update
curl -X POST "https://yoursite.com/wp-json/cocart/preview/checkout" \
-H "Cart-Key: your-cart-key-here" \
-H "Content-Type: application/json" \
-d '{
"billing_address": {
"first_name": "John",
"last_name": "Doe",
"email": "[email protected] ",
"phone": "555-1234",
"address_1": "123 Main St",
"address_2": "Apt 4B",
"city": "Anytown",
"state": "CA",
"postcode": "12345",
"country": "US"
}
}'
Update Billing Address
Update Payment and Shipping Methods
$cart_key = 'your-cart-key-here' ;
$billing_data = array (
'billing_address' => array (
'first_name' => 'John' ,
'last_name' => 'Doe' ,
'email' => '[email protected] ' ,
'phone' => '555-1234' ,
'address_1' => '123 Main St' ,
'city' => 'Anytown' ,
'state' => 'CA' ,
'postcode' => '12345' ,
'country' => 'US' ,
)
);
$response = wp_remote_post ( 'https://yoursite.com/wp-json/cocart/preview/checkout' , array (
'headers' => array (
'Cart-Key' => $cart_key ,
'Content-Type' => 'application/json' ,
),
'body' => json_encode ( $billing_data ),
'timeout' => 30 ,
) );
if ( ! is_wp_error ( $response ) ) {
$result = json_decode ( wp_remote_retrieve_body ( $response ), true );
if ( isset ( $result [ 'success' ] ) && $result [ 'success' ] ) {
echo 'Billing address updated successfully' ;
}
}
Update Billing Address
Complete Checkout Form Update
const cartKey = 'your-cart-key-here' ;
const billingData = {
billing_address: {
first_name: 'John' ,
last_name: 'Doe' ,
email: '[email protected] ' ,
phone: '555-1234' ,
address_1: '123 Main St' ,
city: 'Anytown' ,
state: 'CA' ,
postcode: '12345' ,
country: 'US'
}
};
fetch ( 'https://yoursite.com/wp-json/cocart/preview/checkout' , {
method: 'POST' ,
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( billingData )
})
. then ( response => response . json ())
. then ( data => {
if ( data . success ) {
console . log ( 'Billing address updated successfully' );
}
})
. catch ( error => {
console . error ( 'Update error:' , error );
});
Process Checkout
Complete the checkout process to create an order and process payment.
Process Checkout (Guest)
Process Checkout (Registered User)
curl -X PUT "https://yoursite.com/wp-json/cocart/preview/checkout" \
-H "Cart-Key: your-cart-key-here" \
-H "Content-Type: application/json" \
-d '{
"billing_address": {
"first_name": "John",
"last_name": "Doe",
"email": "[email protected] ",
"phone": "555-1234",
"address_1": "123 Main St",
"city": "Anytown",
"state": "CA",
"postcode": "12345",
"country": "US"
},
"payment_method": "stripe",
"shipping_method": "flat_rate:1"
}'
Process Guest Checkout
Process Registered User Checkout
$cart_key = 'your-cart-key-here' ;
$checkout_data = array (
'billing_address' => array (
'first_name' => 'John' ,
'last_name' => 'Doe' ,
'email' => '[email protected] ' ,
'phone' => '555-1234' ,
'address_1' => '123 Main St' ,
'city' => 'Anytown' ,
'state' => 'CA' ,
'postcode' => '12345' ,
'country' => 'US' ,
),
'payment_method' => 'stripe' ,
'shipping_method' => 'flat_rate:1'
);
$response = wp_remote_request ( 'https://yoursite.com/wp-json/cocart/preview/checkout' , array (
'method' => 'PUT' ,
'headers' => array (
'Cart-Key' => $cart_key ,
'Content-Type' => 'application/json' ,
),
'body' => json_encode ( $checkout_data ),
'timeout' => 60 , // Longer timeout for checkout processing
) );
if ( ! is_wp_error ( $response ) ) {
$result = json_decode ( wp_remote_retrieve_body ( $response ), true );
if ( isset ( $result [ 'order_id' ] ) ) {
$order_id = $result [ 'order_id' ];
$order_key = $result [ 'order_key' ];
$payment_status = $result [ 'payment_result' ][ 'payment_status' ];
if ( $payment_status === 'success' ) {
echo "Order #{ $order_id } created successfully!" ;
// Redirect if needed
if ( isset ( $result [ 'payment_result' ][ 'redirect_url' ] ) ) {
$redirect_url = $result [ 'payment_result' ][ 'redirect_url' ];
wp_redirect ( $redirect_url );
}
}
}
}
Process Guest Checkout
Complete Checkout Handler
const cartKey = 'your-cart-key-here' ;
const checkoutData = {
billing_address: {
first_name: 'John' ,
last_name: 'Doe' ,
email: '[email protected] ' ,
phone: '555-1234' ,
address_1: '123 Main St' ,
city: 'Anytown' ,
state: 'CA' ,
postcode: '12345' ,
country: 'US'
},
payment_method: 'stripe' ,
shipping_method: 'flat_rate:1'
};
fetch ( 'https://yoursite.com/wp-json/cocart/preview/checkout' , {
method: 'PUT' ,
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( checkoutData )
})
. then ( response => response . json ())
. then ( data => {
if ( data . order_id ) {
console . log ( `Order # ${ data . order_id } created successfully!` );
// Handle payment result
if ( data . payment_result . payment_status === 'success' ) {
alert ( 'Payment successful!' );
// Redirect to thank you page or handle redirect
if ( data . payment_result . redirect_url ) {
window . location . href = data . payment_result . redirect_url ;
}
} else if ( data . payment_result . payment_status === 'failed' ) {
alert ( 'Payment failed: ' + data . payment_result . message );
}
}
})
. catch ( error => {
console . error ( 'Checkout error:' , error );
alert ( 'Checkout failed. Please try again.' );
});
Response Examples
Successful Checkout Response
{
"order_id" : 123 ,
"status" : "processing" ,
"order_key" : "wc_order_abc123def456" ,
"order_number" : "123" ,
"payment_result" : {
"payment_status" : "success" ,
"redirect_url" : "https://yoursite.com/checkout/order-received/123/?key=wc_order_abc123def456" ,
"message" : "Payment completed successfully"
},
"billing_address" : {
"first_name" : "John" ,
"last_name" : "Doe" ,
"email" : "[email protected] " ,
"address_1" : "123 Main St" ,
"city" : "Anytown" ,
"state" : "CA" ,
"postcode" : "12345" ,
"country" : "US"
},
"cart_key" : null
}
Error Response Example
{
"code" : "cocart_checkout_empty_cart" ,
"message" : "Cannot checkout with empty cart." ,
"data" : {
"status" : 400
}
}
Advanced Usage
Payment Methods Integration
Get available payment methods before showing checkout form:
curl -X GET "https://yoursite.com/wp-json/cocart/preview/checkout/payment-methods" \
-H "Cart-Key: your-cart-key-here" \
-H "Content-Type: application/json"
$response = wp_remote_get ( 'https://yoursite.com/wp-json/cocart/preview/checkout/payment-methods' , array (
'headers' => array (
'Cart-Key' => $cart_key ,
'Content-Type' => 'application/json' ,
)
) );
if ( ! is_wp_error ( $response ) ) {
$payment_methods = json_decode ( wp_remote_retrieve_body ( $response ), true );
foreach ( $payment_methods as $method_id => $method ) {
echo "<option value='{ $method_id }'>{ $method ['title']}</option>" ;
}
}
async function getPaymentMethods () {
const cartKey = localStorage . getItem ( 'cart_key' );
const response = await fetch ( 'https://yoursite.com/wp-json/cocart/preview/checkout/payment-methods' , {
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
}
});
const methods = await response . json ();
// Populate payment method select
const select = document . getElementById ( 'payment-method' );
Object . entries ( methods ). forEach (([ id , method ]) => {
const option = document . createElement ( 'option' );
option . value = id ;
option . textContent = method . title ;
select . appendChild ( option );
});
}
Payment Context for Client-Side Processing
For payment gateways that require client-side processing (like Stripe Elements):
curl -X POST "https://yoursite.com/wp-json/cocart/preview/checkout/payment-context" \
-H "Cart-Key: your-cart-key-here" \
-H "Content-Type: application/json" \
-d '{"payment_method": "stripe"}'
async function createPaymentContext ( paymentMethod ) {
const cartKey = localStorage . getItem ( 'cart_key' );
const response = await fetch ( 'https://yoursite.com/wp-json/cocart/preview/checkout/payment-context' , {
method: 'POST' ,
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({ payment_method: paymentMethod })
});
const context = await response . json ();
if ( context . client_secret ) {
// Use with Stripe Elements
const stripe = Stripe ( context . public_key );
const elements = stripe . elements ({
clientSecret: context . client_secret
});
// Initialize payment element
const paymentElement = elements . create ( 'payment' );
paymentElement . mount ( '#payment-element' );
}
return context ;
}
Payment Processing
The checkout API supports both simple server-side payment methods and complex client-side payment processing. The approach depends on your payment gateway:
Server-Side Payment Methods
For payment methods that process entirely server-side (Bank Transfer, Check, COD), you only need to specify the payment method:
const checkoutData = {
billing_address: billingAddress ,
payment_method: 'bacs' , // Bank transfer
shipping_method: 'flat_rate:1'
};
await processCheckout ( checkoutData );
Client-Side Payment Methods
For gateways requiring client-side processing (Stripe, PayPal, Square), you need to:
Create Payment Context - Get gateway configuration from the server
Collect Payment Details - Use the gateway’s SDK to securely collect payment info
Process Payment - Handle the payment with the gateway
Submit Checkout - Include payment data in your checkout request
Payment Gateway Integration Guides
For detailed integration examples with specific payment gateways, see our dedicated tutorials:
Basic Payment Data Structure
When submitting checkout with payment data, include the gateway-specific information:
const checkoutData = {
billing_address: {
first_name: 'John' ,
last_name: 'Doe' ,
email: '[email protected] ' ,
// ... other address fields
},
payment_method: 'stripe' , // Gateway ID
shipping_method: 'flat_rate:1' ,
// Gateway-specific payment data (see individual tutorials)
payment_data: {
payment_intent_id: 'pi_1234567890' ,
payment_method_id: 'pm_1234567890' ,
// ... other gateway-specific fields
}
};
Error Handling
Common error scenarios and how to handle them:
Empty Cart Code : cocart_checkout_empty_cartSolution : Redirect user to shop or cart page
Invalid Address Code : cocart_checkout_invalid_addressSolution : Validate and correct address fields
Payment Failed Code : cocart_payment_failedSolution : Display error message and allow retry
Insufficient Stock Code : cocart_insufficient_stockSolution : Update quantities or remove unavailable items
function handleCheckoutError ( error ) {
switch ( error . code ) {
case 'cocart_checkout_empty_cart' :
window . location . href = '/shop' ;
break ;
case 'cocart_checkout_invalid_address' :
highlightInvalidFields ( error . data . invalid_fields );
showError ( 'Please correct the highlighted fields' );
break ;
case 'cocart_payment_failed' :
showError ( `Payment failed: ${ error . data . message } ` );
enableRetryButton ();
break ;
case 'cocart_insufficient_stock' :
updateCartQuantities ( error . data . stock_data );
showError ( 'Some items have limited stock. Cart updated.' );
break ;
default :
showError ( 'An unexpected error occurred. Please try again.' );
}
}
Payment Processing Approaches
Development vs Production
The payment methods endpoint provides different levels of information based on user permissions:
For users with admin permissions , the payment methods endpoint includes debug information to help understand gateway configurations:// Only available to admin users
const response = await fetch ( '/wp-json/cocart/preview/checkout/payment-methods' , {
headers: {
'Authorization' : `Bearer ${ adminJwtToken } ` , // Admin user required
'Cart-Key' : cartKey
}
});
const data = await response . json ();
console . log ( data . debug_info ); // Gateway configuration details
Response with debug info: {
"payment_methods" : {
"stripe" : {
"id" : "stripe" ,
"title" : "Credit Card" ,
"enabled" : true
}
},
"debug_info" : {
"payment_context" : {
"stripe" : {
"publishable_key" : "pk_test_xxx" ,
"webhook_endpoint" : "/wc-api/stripe" ,
"gateway_mode" : "test"
}
},
"note" : "Debug information - DO NOT use in production"
}
}
Debug information is only available to users with manage_options capability and should never be used in production applications.
For production applications , use direct gateway integration with the checkout API:// 1. Initialize gateway SDK with your store's credentials
const stripe = Stripe ( 'pk_live_your_publishable_key' );
const elements = stripe . elements ();
// 2. Create payment method using gateway SDK
const { paymentMethod , error } = await stripe . createPaymentMethod ({
type: 'card' ,
card: cardElement ,
billing_details: {
name: 'John Doe' ,
email: '[email protected] ' ,
},
});
if ( error ) {
console . error ( 'Payment method creation failed:' , error );
return ;
}
// 3. Process checkout with payment method reference
const checkoutResponse = await fetch ( '/wp-json/cocart/preview/checkout' , {
method: 'PUT' ,
headers: {
'Cart-Key' : cartKey ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
billing_address: billingData ,
payment_method: 'stripe' ,
payment_method_data: {
payment_method: paymentMethod . id // Only pass the reference
}
})
});
Benefits of this approach:
Security : Payment details never touch your servers
PCI Compliance : Gateway handles sensitive data
Performance : No extra API calls for payment contexts
Reliability : Direct integration with gateway SDKs
Gateway Configuration Alignment
Important : Your frontend gateway configuration must match your WooCommerce store settings:
WooCommerce Store Settings: WooCommerce → Payments → Stripe
- Publishable Key: pk_live_abc123...
- Secret Key: sk_live_xyz789...
- Webhook Endpoint: yourstore.com/wc-api/stripe
Frontend Implementation: // Must use the SAME publishable key
const stripe = Stripe ( 'pk_live_abc123...' ); // Same as store settings
WooCommerce Store Settings: WooCommerce → Payments → PayPal
- Client ID: your_paypal_client_id
- Environment: live
Frontend Implementation: // Must use the SAME client ID and environment
paypal . Buttons ({
env: 'live' , // Same as store settings
client: {
live: 'your_paypal_client_id' // Same as store settings
}
});
Rate Limiting for Checkout Operations
The checkout API includes enhanced rate limiting to prevent abuse:
// Default rate limits (can be customized via filters)
- GET / checkout : 20 requests per minute
- PUT / checkout : 5 requests per minute
- GET / payment - methods : 30 requests per minute
- GET / payment - methods ( with debug ): 1 request per minute
Use the cocart_api_rate_limits filter to customize limits for your application:
add_filter ( 'cocart_api_rate_limits' , function ( $limits ) {
$limits [ 'checkout_get' ] = 50 ; // Increase GET limit
$limits [ 'checkout_put' ] = 3 ; // Decrease POST limit
return $limits ;
});
Best Practices
Security
Never expose consumer secrets in client-side code
Use environment variables for storing API credentials
Rotate consumer keys regularly and monitor usage
Implement rate limiting to prevent abuse
Log authentication failures for security monitoring
Validate cart session ownership to prevent cart hijacking
Extract customer context from cart sessions rather than relying on client-provided IDs
Sanitize all input data server-side regardless of client validation
Use HTTPS exclusively for all API communications
Implement proper session management for cart keys with sufficient entropy
Clear sensitive data after successful transactions
Follow PCI DSS guidelines for payment data handling
Use payment gateway tokenization instead of storing card data
Implement webhook validation for payment confirmations
Monitor for fraudulent patterns and implement blocking
Use secure payment contexts with time-limited validity
Use longer timeouts for checkout processing (60+ seconds)
Implement request queuing to handle rate limits gracefully
Cache payment methods and shipping options when possible
Batch API calls to minimize round trips
Monitor API response times and optimize slow endpoints
User Experience
Show progress indicators for multi-step processes
Handle payment redirects gracefully with proper loading states
Provide multiple payment options to reduce abandonment
Support guest and registered checkout flows seamlessly
Implement proper success/failure handling with clear next steps
Development
Test with different payment gateways and edge cases
Use dedicated test/sandbox environments for integration testing
Implement automated testing for critical checkout paths
Test rate limiting and error scenarios thoroughly
Validate webhook handling with test data
Follow WordPress and WooCommerce coding standards
Implement proper error logging without exposing sensitive data
Use version control for API changes and rollbacks
Document API integrations thoroughly for team knowledge
Monitor production performance and error rates
Consumer Key Management
Use descriptive names for different applications/environments
Set appropriate permissions (read, write, read/write)
Generate separate keys for each application or environment
Document key purposes and ownership for team management
Store keys in secure configuration (environment variables, secure vaults)
Never commit keys to version control systems
Rotate keys periodically as part of security maintenance
Monitor key usage for suspicious patterns
Revoke compromised keys immediately and generate replacements
Track API usage patterns per consumer key
Set up alerts for unusual activity or rate limit hits
Monitor authentication failures and investigate patterns
Review key permissions regularly for principle of least privilege
Maintain audit logs for compliance and troubleshooting
Remember to test your checkout implementation thoroughly with different scenarios including successful payments, failed payments, address validation, and edge cases like empty carts or out-of-stock items.