Checkout API
The Checkout API enables you to convert shopping carts into orders, collect customer information, and process payments. It provides a complete checkout flow for headless and traditional WooCommerce implementations.
Overview
The Checkout API allows you to:
Retrieve checkout session data
Update customer billing and shipping information
Select payment methods
Add order notes and custom fields
Process payment and create orders
Handle payment gateway integration
All checkout endpoints require either a Nonce Token or a Cart Token for security. Checkout operations will fail without proper authentication.
Base Endpoint
All checkout endpoints use the base path:
/wp-json/wc/store/v1/checkout
Authentication
Nonce Tokens
Checkout requires valid nonce tokens for all requests:
curl --header "Nonce: 12345" \
--request GET \
https://example-store.com/wp-json/wc/store/v1/checkout
Generate nonces using:
$nonce = wp_create_nonce ( 'wc_store_api' );
The nonce is updated with each response. Always use the latest nonce from the response headers for your next request.
Cart Tokens
For headless implementations, use Cart Tokens:
curl --header "Cart-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
--request POST \
https://example-store.com/wp-json/wc/store/v1/checkout
Cart Tokens eliminate the need for nonces in headless environments.
Get Checkout Data
Retrieve the current checkout session, including a draft order created from the cart.
GET /wp-json/wc/store/v1/checkout
Request
curl --header "Nonce: 12345" \
--request GET \
"https://example-store.com/wp-json/wc/store/v1/checkout"
Response
{
"order_id" : 146 ,
"status" : "checkout-draft" ,
"order_key" : "wc_order_VPffqyvgWVqWL" ,
"order_number" : "146" ,
"customer_note" : "" ,
"customer_id" : 1 ,
"billing_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US" ,
"email" : "[email protected] " ,
"phone" : "555-2368"
},
"shipping_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US"
},
"payment_method" : "" ,
"payment_result" : {
"payment_status" : "" ,
"payment_details" : [],
"redirect_url" : ""
},
"additional_fields" : {}
}
Response Fields
Draft order ID created from the cart
Order status (typically checkout-draft until payment is processed)
Unique order key for verification
Customer billing address with email and phone
Customer shipping address
Selected payment method ID (empty until selected)
Payment processing results (populated after POST request)
Custom fields added by plugins or themes
Update Checkout Data
Update checkout information without processing payment. This is useful for persisting checkout fields as the customer fills them out.
PUT /wp-json/wc/store/v1/checkout
Parameters
The ID of the selected payment method (e.g., “bacs”, “cheque”, “stripe”)
Customer notes for the order
Custom fields with namespace/key structure (e.g., plugin-namespace/field-name)
__experimental_calc_totals
Set to true to recalculate cart totals (default: false)
Request
curl --header "Nonce: 12345" \
--request PUT \
--header "Content-Type: application/json" \
--data '{
"payment_method": "bacs",
"order_notes": "Please leave package on back porch",
"additional_fields": {
"plugin-namespace/delivery-instructions": "Call on arrival"
}
}' \
"https://example-store.com/wp-json/wc/store/v1/checkout?__experimental_calc_totals=true"
Response
{
"order_id" : 1486 ,
"status" : "checkout-draft" ,
"order_key" : "wc_order_KLpMaJ054PVlb" ,
"order_number" : "1486" ,
"customer_note" : "Please leave package on back porch" ,
"customer_id" : 1 ,
"billing_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US" ,
"email" : "[email protected] " ,
"phone" : "555-2368"
},
"shipping_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US"
},
"payment_method" : "bacs" ,
"payment_result" : null ,
"additional_fields" : {
"plugin-namespace/delivery-instructions" : "Call on arrival"
},
"__experimentalCart" : {
"items" : [ ... ],
"totals" : { ... }
},
"extensions" : {}
}
The __experimentalCart field is included when __experimental_calc_totals=true, allowing you to update the cart UI based on checkout changes without an additional request.
Process Order and Payment
Submit final checkout data and process payment to create an order.
POST /wp-json/wc/store/v1/checkout
Parameters
Complete billing address object Show Billing Address Fields
Country code (ISO 3166-1 alpha-2)
Complete shipping address object (same fields as billing except no email)
Payment method ID (e.g., “bacs”, “cheque”, “stripe”, “paypal”)
Payment-specific data required by the payment gateway (structure varies by gateway)
Order notes from the customer
Password for new account creation (if enabled)
Whether to create a new customer account
Request
Basic Payment
React Example
curl --header "Nonce: 12345" \
--request POST \
--header "Content-Type: application/json" \
--data '{
"billing_address": {
"first_name": "Peter",
"last_name": "Venkman",
"company": "",
"address_1": "550 Central Park West",
"address_2": "Corner Penthouse Spook Central",
"city": "New York",
"state": "NY",
"postcode": "10023",
"country": "US",
"email": "[email protected] ",
"phone": "555-2368"
},
"shipping_address": {
"first_name": "Peter",
"last_name": "Venkman",
"company": "",
"address_1": "550 Central Park West",
"address_2": "Corner Penthouse Spook Central",
"city": "New York",
"state": "NY",
"postcode": "10023",
"country": "US"
},
"customer_note": "Test notes on order.",
"payment_method": "cheque",
"payment_data": []
}' \
"https://example-store.com/wp-json/wc/store/v1/checkout"
Response
200 OK - Success
400 Error - Validation Failed
400 Error - Payment Failed
{
"order_id" : 146 ,
"status" : "on-hold" ,
"order_key" : "wc_order_VPffqyvgWVqWL" ,
"order_number" : "146" ,
"customer_note" : "Test notes on order." ,
"customer_id" : 1 ,
"billing_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US" ,
"email" : "[email protected] " ,
"phone" : "555-2368"
},
"shipping_address" : {
"first_name" : "Peter" ,
"last_name" : "Venkman" ,
"company" : "" ,
"address_1" : "550 Central Park West" ,
"address_2" : "Corner Penthouse Spook Central" ,
"city" : "New York" ,
"state" : "NY" ,
"postcode" : "10023" ,
"country" : "US"
},
"payment_method" : "cheque" ,
"payment_result" : {
"payment_status" : "success" ,
"payment_details" : [],
"redirect_url" : "https://example-store.com/checkout/order-received/146/?key=wc_order_VPffqyvgWVqWL"
}
}
Payment Result Object
Payment outcome: “success”, “failure”, “pending”, or “error”
Additional payment information from the gateway
URL to redirect customer after successful checkout (typically order confirmation page)
Checkout Flow
Initialize Checkout
Make a GET request to retrieve the checkout session and pre-fill customer data GET /wc/store/v1/checkout
Collect Information
Display checkout form to collect:
Billing address
Shipping address
Payment method selection
Order notes
Custom fields
Validate and Update
Optionally use PUT requests to persist data and validate fields as the customer fills out the form PUT /wc/store/v1/checkout?__experimental_calc_totals= true
Process Payment
Submit final checkout with POST request POST /wc/store/v1/checkout
Handle Response
On success: Redirect to payment_result.redirect_url
On failure: Display error message and allow retry
Payment Gateway Integration
Different payment gateways require different payment_data structures. Always consult the payment gateway’s documentation for specific requirements.
Example: Stripe Payment Gateway
The WooCommerce Stripe Payment Gateway expects:
{
"payment_method" : "stripe" ,
"payment_data" : [
{
"key" : "stripe_source" ,
"value" : "src_xxxxxxxxxxxxx"
},
{
"key" : "billing_email" ,
"value" : "[email protected] "
},
{
"key" : "billing_first_name" ,
"value" : "Jane"
},
{
"key" : "billing_last_name" ,
"value" : "Doe"
},
{
"key" : "paymentMethod" ,
"value" : "stripe"
},
{
"key" : "paymentRequestType" ,
"value" : "cc"
},
{
"key" : "wc-stripe-new-payment-method" ,
"value" : true
}
]
}
The stripe_source is generated using the Stripe JavaScript SDK :
// Create Stripe source
const { source , error } = await stripe . createSource ({
type: 'card' ,
card: cardElement ,
owner: {
name: billingData . firstName + ' ' + billingData . lastName ,
email: billingData . email
}
});
if ( error ) {
// Handle error
} else {
// Add source.id to payment_data
paymentData . push ({
key: 'stripe_source' ,
value: source . id
});
}
Example: PayPal
PayPal integration typically involves:
Generate PayPal order ID client-side
Include PayPal order ID in payment_data
Gateway validates and captures payment
{
"payment_method" : "paypal" ,
"payment_data" : [
{
"key" : "paypal_order_id" ,
"value" : "1AB23456CD789012E"
}
]
}
Standard Payment Methods
WooCommerce includes built-in payment methods that don’t require additional payment_data:
bacs - Direct bank transfer
cheque - Check payments
cod - Cash on delivery
{
"payment_method" : "bacs" ,
"payment_data" : []
}
Additional Fields
Plugins can add custom checkout fields using the additional_fields parameter:
{
"additional_fields" : {
"plugin-namespace/gift-message" : "Happy Birthday!" ,
"plugin-namespace/gift-wrap" : true ,
"plugin-namespace/delivery-date" : "2024-12-25"
}
}
Fields must use namespaced keys (plugin-namespace/field-name) to avoid conflicts.
Registering Custom Fields
Plugin developers can register custom checkout fields:
use Automattic\WooCommerce\Blocks\ Package ;
use Automattic\WooCommerce\Blocks\Domain\Services\ CheckoutFields ;
add_action ( 'woocommerce_blocks_loaded' , function () {
$checkout_fields = Package :: container () -> get ( CheckoutFields :: class );
$checkout_fields -> register_checkout_field ([
'id' => 'plugin-namespace/gift-message' ,
'label' => 'Gift message' ,
'location' => 'order' ,
'type' => 'text' ,
'required' => false ,
]);
});
Error Handling
Common Error Codes
Code Description woocommerce_rest_checkout_invalid_addressBilling or shipping address validation failed woocommerce_rest_checkout_payment_errorPayment processing failed woocommerce_rest_checkout_missing_payment_methodNo payment method selected woocommerce_rest_invalid_nonceNonce token is invalid or expired woocommerce_rest_checkout_cart_emptyCannot checkout with empty cart woocommerce_rest_checkout_invalid_cartCart contains invalid items
Handling Validation Errors
Validation errors include field-specific details in data.params:
{
"code" : "woocommerce_rest_checkout_invalid_address" ,
"message" : "Invalid billing address provided." ,
"data" : {
"status" : 400 ,
"params" : {
"billing_address.email" : "Invalid email address" ,
"billing_address.postcode" : "Postcode is required"
}
}
}
Display these errors next to the relevant form fields:
try {
const order = await processCheckout ( formData );
window . location . href = order . payment_result . redirect_url ;
} catch ( error ) {
const errorData = await error . response . json ();
if ( errorData . data ?. params ) {
// Display field-specific errors
Object . keys ( errorData . data . params ). forEach ( field => {
const errorMessage = errorData . data . params [ field ];
displayFieldError ( field , errorMessage );
});
} else {
// Display general error
displayError ( errorData . message );
}
}
Order Statuses
After successful checkout, orders are assigned a status based on the payment method:
Status Description checkout-draftTemporary status during checkout (not a real order yet) pendingOrder received, awaiting payment processingPayment received, order is being prepared on-holdAwaiting confirmation (e.g., bank transfer) completedOrder fulfilled and complete cancelledOrder cancelled by customer or admin refundedOrder refunded failedPayment failed or declined
Most payment gateways set orders to processing or on-hold after successful checkout.
Retrieving Order Details
After checkout, customers can retrieve their order using the Order API:
GET /wp-json/wc/store/v1/order/:id
This requires the order ID and key for authorization:
curl --header "Nonce: 12345" \
"https://example-store.com/wp-json/wc/store/v1/order/146?key=wc_order_VPffqyvgWVqWL"
Customers can only access their own orders. The order key provides authorization without requiring authentication.
Best Practices
Validate Before Submitting
Use PUT requests during checkout to validate data before final submission:
// Validate address when customer enters it
async function validateAddress ( address ) {
await fetch ( '/wp-json/wc/store/v1/checkout' , {
method: 'PUT' ,
headers: {
'Content-Type' : 'application/json' ,
'Nonce' : nonce
},
body: JSON . stringify ({ billing_address: address })
});
}
Handle Payment Redirects
Some payment gateways redirect customers to external sites. Always use payment_result.redirect_url:
const result = await processCheckout ( formData );
if ( result . payment_result . payment_status === 'success' ) {
window . location . href = result . payment_result . redirect_url ;
}
Show Loading States
Checkout can take several seconds. Always show loading indicators:
async function handleCheckout ( formData ) {
setLoading ( true );
try {
const order = await processCheckout ( formData );
window . location . href = order . payment_result . redirect_url ;
} catch ( error ) {
displayError ( error . message );
} finally {
setLoading ( false );
}
}
Retry Failed Payments
Allow customers to retry after payment failure:
if ( result . payment_result . payment_status === 'failure' ) {
displayError ( 'Payment failed. Please check your payment details and try again.' );
// Keep checkout form visible for retry
} else {
window . location . href = result . payment_result . redirect_url ;
}
Security Considerations
Never store payment card details on your server. Use payment gateway SDKs to tokenize payment information client-side.
PCI Compliance
Use payment gateway JavaScript SDKs to collect card details
Never send raw card numbers to your server
Use tokens or source IDs in payment_data
Nonce Expiration
Nonces expire after 12-24 hours. If checkout fails with invalid nonce error:
Refresh the nonce by making a GET request
Retry the checkout with the new nonce
HTTPS Required
Always use HTTPS for checkout operations to protect customer data in transit.
Next Steps
Cart API Learn about cart management before checkout
Store API Overview Back to Store API introduction
Payment Gateways Browse available payment gateway extensions
Extending Checkout Learn how to extend the checkout experience