> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cocartapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Using the Checkout API

> Learn how to implement the complete checkout process with CoCart's Preview API

<Warning>
  This tutorial was written by [Claude Code (an AI)](https://claude.com/product/claude-code) 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.
</Warning>

<Note>
  This guide covers CoCart Preview API features. The checkout endpoints require CoCart v4.6 and up with the Preview API enabled.
</Note>

## 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:

1. A valid cart with items added
2. Proper authentication (Cart Key, Basic Auth, or JWT)
3. Required customer information (billing address at minimum)
4. Available payment and shipping methods configured in WooCommerce

## Basic Checkout Flow

<Steps>
  <Step title="Get Checkout Data">
    Retrieve current checkout information to display available options
  </Step>

  <Step title="Update Checkout Information">
    Set billing/shipping addresses and selected payment/shipping methods
  </Step>

  <Step title="Process Checkout">
    Complete the transaction and create the order
  </Step>
</Steps>

## Authentication

The CoCart Checkout API uses WooCommerce consumer key/secret authentication for secure access:

<CardGroup cols={2}>
  <Card title="Consumer Keys" icon="key" href="/tutorials/consumer-key-setup">
    **Required for all requests** - WooCommerce API keys provide secure, authenticated access
  </Card>

  <Card title="Customer Context" icon="user">
    **Optional customer ID** - Include for registered customer features and personalization
  </Card>
</CardGroup>

### Authentication Methods

* **Consumer Key/Secret**: Required for all API access (see [Consumer Key Setup](/tutorials/consumer-key-setup))
* **Cart Key**: Identifies the customer's cart session and automatically provides customer context for registered users

### Request Structure

```javascript theme={"system"}
// 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'
};
```

<Note>
  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.
</Note>

## API Endpoints

### Get Checkout Data

Retrieve current checkout information including cart contents, totals, addresses, and available shipping/payment methods.

<Tabs>
  <Tab title="cURL">
    ```bash theme={"system"}
    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"
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={"system"}
    $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'];
        }
    }
    ```
  </Tab>

  <Tab title="JavaScript">
    <CodeGroup>
      ```javascript Guest Checkout (Fetch API) theme={"system"}
      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);
      });
      ```

      ```javascript Registered Customer (Async/Await) theme={"system"}
      async function getCheckoutData() {
          const cartKey = localStorage.getItem('cart_key');

          const url = new URL('https://yoursite.com/wp-json/cocart/preview/checkout');
          url.searchParams.append('consumer_key', 'ck_1234567890abcdef');
          url.searchParams.append('consumer_secret', 'cs_1234567890abcdef');

          try {
              const response = await fetch(url.toString(), {
                  method: 'GET',
                  headers: {
                      'Cart-Key': cartKey,
                      'Content-Type': 'application/json',
                  },
              });

              const checkoutData = await response.json();

              if (checkoutData.needs_payment) {
                  // Show payment methods
                  displayPaymentMethods(checkoutData.payment_methods);
              }

              if (checkoutData.customer_data) {
                  // Handle customer-specific data
                  prefillCustomerInfo(checkoutData.customer_data);
              }

              return checkoutData;
          } catch (error) {
              console.error('Checkout data fetch error:', error);
              throw error;
          }
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### Update Checkout Information

Update checkout details such as billing address, shipping address, payment method, or shipping method.

<Tabs>
  <Tab title="cURL">
    <CodeGroup>
      ```bash Update Billing Address theme={"system"}
      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": "john@example.com",
            "phone": "555-1234",
            "address_1": "123 Main St",
            "address_2": "Apt 4B",
            "city": "Anytown",
            "state": "CA",
            "postcode": "12345",
            "country": "US"
          }
        }'
      ```

      ```bash Update Shipping and Payment Method theme={"system"}
      curl -X POST "https://yoursite.com/wp-json/cocart/preview/checkout" \
        -H "Authorization: Basic $(echo -n 'username:password' | base64)" \
        -H "Content-Type: application/json" \
        -d '{
          "shipping_method": "flat_rate:1",
          "payment_method": "stripe"
        }'
      ```

      ```bash Complete Address Update theme={"system"}
      curl -X POST "https://yoursite.com/wp-json/cocart/preview/checkout" \
        -H "Authorization: Bearer your-jwt-token" \
        -H "Content-Type: application/json" \
        -d '{
          "billing_address": {
            "first_name": "Jane",
            "last_name": "Smith",
            "email": "jane@example.com",
            "address_1": "456 Oak Ave",
            "city": "Springfield",
            "state": "NY",
            "postcode": "67890",
            "country": "US"
          },
          "shipping_address": {
            "first_name": "Jane",
            "last_name": "Smith",
            "address_1": "789 Pine St",
            "city": "Springfield",
            "state": "NY",
            "postcode": "67890",
            "country": "US"
          }
        }'
      ```
    </CodeGroup>
  </Tab>

  <Tab title="PHP">
    <CodeGroup>
      ```php Update Billing Address theme={"system"}
      $cart_key = 'your-cart-key-here';
      $billing_data = array(
          'billing_address' => array(
              'first_name' => 'John',
              'last_name' => 'Doe',
              'email' => 'john@example.com',
              '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';
          }
      }
      ```

      ```php Update Payment and Shipping Methods theme={"system"}
      $credentials = base64_encode('username:password');
      $method_data = array(
          'payment_method' => 'stripe',
          'shipping_method' => 'flat_rate:1'
      );

      $response = wp_remote_post( 'https://yoursite.com/wp-json/cocart/preview/checkout', array(
          'headers' => array(
              'Authorization' => 'Basic ' . $credentials,
              'Content-Type' => 'application/json',
          ),
          'body' => json_encode( $method_data ),
          'timeout' => 30,
      ) );

      if ( ! is_wp_error( $response ) ) {
          $result = json_decode( wp_remote_retrieve_body( $response ), true );
          echo 'Methods updated: ' . $result['message'];
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="JavaScript">
    <CodeGroup>
      ```javascript Update Billing Address theme={"system"}
      const cartKey = 'your-cart-key-here';
      const billingData = {
          billing_address: {
              first_name: 'John',
              last_name: 'Doe',
              email: 'john@example.com',
              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);
      });
      ```

      ```javascript Complete Checkout Form Update theme={"system"}
      async function updateCheckoutInfo(formData) {
          const jwtToken = localStorage.getItem('cocart_token');

          try {
              const response = await fetch('https://yoursite.com/wp-json/cocart/preview/checkout', {
                  method: 'POST',
                  headers: {
                      'Authorization': `Bearer ${jwtToken}`,
                      'Content-Type': 'application/json',
                  },
                  body: JSON.stringify({
                      billing_address: formData.billing,
                      shipping_address: formData.shipping,
                      payment_method: formData.paymentMethod,
                      shipping_method: formData.shippingMethod
                  })
              });

              const result = await response.json();

              if (result.success) {
                  console.log('Checkout information updated');
                  return true;
              } else {
                  throw new Error(result.message || 'Update failed');
              }
          } catch (error) {
              console.error('Checkout update error:', error);
              throw error;
          }
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### Process Checkout

Complete the checkout process to create an order and process payment.

<Tabs>
  <Tab title="cURL">
    <CodeGroup>
      ```bash Process Checkout (Guest) theme={"system"}
      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": "john@example.com",
            "phone": "555-1234",
            "address_1": "123 Main St",
            "city": "Anytown",
            "state": "CA",
            "postcode": "12345",
            "country": "US"
          },
          "payment_method": "stripe",
          "shipping_method": "flat_rate:1"
        }'
      ```

      ```bash Process Checkout (Registered User) theme={"system"}
      curl -X PUT "https://yoursite.com/wp-json/cocart/preview/checkout" \
        -H "Authorization: Basic $(echo -n 'username:password' | base64)" \
        -H "Content-Type: application/json" \
        -d '{
          "billing_address": {
            "first_name": "Jane",
            "last_name": "Smith",
            "email": "jane@example.com",
            "address_1": "456 Oak Ave",
            "city": "Springfield",
            "state": "NY",
            "postcode": "67890",
            "country": "US"
          },
          "shipping_address": {
            "first_name": "Jane",
            "last_name": "Smith",
            "address_1": "789 Pine St",
            "city": "Springfield",
            "state": "NY",
            "postcode": "67890",
            "country": "US"
          },
          "payment_method": "paypal",
          "shipping_method": "free_shipping:2"
        }'
      ```
    </CodeGroup>
  </Tab>

  <Tab title="PHP">
    <CodeGroup>
      ```php Process Guest Checkout theme={"system"}
      $cart_key = 'your-cart-key-here';
      $checkout_data = array(
          'billing_address' => array(
              'first_name' => 'John',
              'last_name' => 'Doe',
              'email' => 'john@example.com',
              '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 );
                  }
              }
          }
      }
      ```

      ```php Process Registered User Checkout theme={"system"}
      $credentials = base64_encode('username:password');
      $checkout_data = array(
          'billing_address' => array(
              'first_name' => 'Jane',
              'last_name' => 'Smith',
              'email' => 'jane@example.com',
              'address_1' => '456 Oak Ave',
              'city' => 'Springfield',
              'state' => 'NY',
              'postcode' => '67890',
              'country' => 'US',
          ),
          'shipping_address' => array(
              'first_name' => 'Jane',
              'last_name' => 'Smith',
              'address_1' => '789 Pine St',
              'city' => 'Springfield',
              'state' => 'NY',
              'postcode' => '67890',
              'country' => 'US',
          ),
          'payment_method' => 'paypal',
          'shipping_method' => 'free_shipping:2'
      );

      $response = wp_remote_request( 'https://yoursite.com/wp-json/cocart/preview/checkout', array(
          'method' => 'PUT',
          'headers' => array(
              'Authorization' => 'Basic ' . $credentials,
              'Content-Type' => 'application/json',
          ),
          'body' => json_encode( $checkout_data ),
          'timeout' => 60,
      ) );

      if ( ! is_wp_error( $response ) ) {
          $result = json_decode( wp_remote_retrieve_body( $response ), true );

          // Handle different payment statuses
          switch ( $result['payment_result']['payment_status'] ) {
              case 'success':
                  echo "Payment successful! Order: " . $result['order_number'];
                  break;
              case 'failed':
                  echo "Payment failed: " . $result['payment_result']['message'];
                  break;
              case 'no_payment_required':
                  echo "Order completed - no payment required";
                  break;
          }
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="JavaScript">
    <CodeGroup>
      ```javascript Process Guest Checkout theme={"system"}
      const cartKey = 'your-cart-key-here';
      const checkoutData = {
          billing_address: {
              first_name: 'John',
              last_name: 'Doe',
              email: 'john@example.com',
              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.');
      });
      ```

      ```javascript Complete Checkout Handler theme={"system"}
      async function processCheckout(checkoutData) {
          const jwtToken = localStorage.getItem('cocart_token');

          try {
              // Show loading state
              showLoadingState('Processing checkout...');

              const response = await fetch('https://yoursite.com/wp-json/cocart/preview/checkout', {
                  method: 'PUT',
                  headers: {
                      'Authorization': `Bearer ${jwtToken}`,
                      'Content-Type': 'application/json',
                  },
                  body: JSON.stringify(checkoutData)
              });

              const result = await response.json();

              if (!response.ok) {
                  throw new Error(result.message || `HTTP ${response.status}`);
              }

              // Handle successful checkout
              if (result.order_id) {
                  // Clear cart from localStorage if needed
                  localStorage.removeItem('cart_key');

                  // Handle different payment statuses
                  switch (result.payment_result.payment_status) {
                      case 'success':
                          showSuccessMessage(`Order #${result.order_number} completed successfully!`);
                          if (result.payment_result.redirect_url) {
                              setTimeout(() => {
                                  window.location.href = result.payment_result.redirect_url;
                              }, 2000);
                          }
                          break;

                      case 'failed':
                          showErrorMessage('Payment failed: ' + result.payment_result.message);
                          break;

                      case 'no_payment_required':
                          showSuccessMessage(`Order #${result.order_number} completed - no payment required`);
                          break;
                  }

                  return result;
              }

          } catch (error) {
              console.error('Checkout processing error:', error);
              showErrorMessage('Checkout failed. Please try again.');
              throw error;
          } finally {
              hideLoadingState();
          }
      }

      // Example usage
      const checkoutForm = document.getElementById('checkout-form');
      checkoutForm.addEventListener('submit', async (e) => {
          e.preventDefault();

          const formData = new FormData(checkoutForm);
          const checkoutData = {
              billing_address: {
                  first_name: formData.get('billing_first_name'),
                  last_name: formData.get('billing_last_name'),
                  email: formData.get('billing_email'),
                  phone: formData.get('billing_phone'),
                  address_1: formData.get('billing_address_1'),
                  city: formData.get('billing_city'),
                  state: formData.get('billing_state'),
                  postcode: formData.get('billing_postcode'),
                  country: formData.get('billing_country')
              },
              payment_method: formData.get('payment_method'),
              shipping_method: formData.get('shipping_method')
          };

          await processCheckout(checkoutData);
      });
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Response Examples

### Successful Checkout Response

```json theme={"system"}
{
  "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": "john@example.com",
    "address_1": "123 Main St",
    "city": "Anytown",
    "state": "CA",
    "postcode": "12345",
    "country": "US"
  },
  "cart_key": null
}
```

### Error Response Example

```json theme={"system"}
{
  "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:

<Tabs>
  <Tab title="cURL">
    ```bash theme={"system"}
    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"
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={"system"}
    $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>";
        }
    }
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={"system"}
    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);
        });
    }
    ```
  </Tab>
</Tabs>

### Payment Context for Client-Side Processing

For payment gateways that require client-side processing (like Stripe Elements):

<Tabs>
  <Tab title="cURL">
    ```bash theme={"system"}
    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"}'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={"system"}
    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;
    }
    ```
  </Tab>
</Tabs>

## 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:

```javascript theme={"system"}
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:

1. **Create Payment Context** - Get gateway configuration from the server
2. **Collect Payment Details** - Use the gateway's SDK to securely collect payment info
3. **Process Payment** - Handle the payment with the gateway
4. **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:

<CardGroup cols={2}>
  <Card title="Stripe Checkout" icon="stripe" href="/tutorials/checkout-stripe">
    Complete Stripe Elements integration with Payment Intents API
  </Card>

  <Card title="PayPal Checkout" icon="paypal" href="/tutorials/checkout-paypal">
    PayPal Buttons integration with order capture flow
  </Card>

  <Card title="Square Checkout" icon="square" href="/tutorials/checkout-square">
    Square Web SDK integration with payment forms
  </Card>

  <Card title="General Payment Processing" icon="credit-card" href="/tutorials/checkout-payment-processing">
    Learn about payment contexts, data structures, and common patterns
  </Card>
</CardGroup>

### Basic Payment Data Structure

When submitting checkout with payment data, include the gateway-specific information:

```javascript theme={"system"}
const checkoutData = {
    billing_address: {
        first_name: 'John',
        last_name: 'Doe',
        email: 'john@example.com',
        // ... 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:

<CardGroup cols={2}>
  <Card title="Empty Cart" icon="shopping-cart">
    **Code**: `cocart_checkout_empty_cart`

    **Solution**: Redirect user to shop or cart page
  </Card>

  <Card title="Invalid Address" icon="map-pin">
    **Code**: `cocart_checkout_invalid_address`

    **Solution**: Validate and correct address fields
  </Card>

  <Card title="Payment Failed" icon="credit-card">
    **Code**: `cocart_payment_failed`

    **Solution**: Display error message and allow retry
  </Card>

  <Card title="Insufficient Stock" icon="package">
    **Code**: `cocart_insufficient_stock`

    **Solution**: Update quantities or remove unavailable items
  </Card>
</CardGroup>

```javascript theme={"system"}
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:

<Tabs>
  <Tab title="Development/Debugging">
    **For users with admin permissions**, the payment methods endpoint includes debug information to help understand gateway configurations:

    ```javascript theme={"system"}
    // 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:**

    ```json theme={"system"}
    {
      "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"
      }
    }
    ```

    <Warning>
      Debug information is only available to users with `manage_options` capability and should never be used in production applications.
    </Warning>
  </Tab>

  <Tab title="Production Implementation">
    **For production applications**, use direct gateway integration with the checkout API:

    ```javascript theme={"system"}
    // 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: 'john@example.com',
      },
    });

    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
  </Tab>
</Tabs>

### Gateway Configuration Alignment

**Important**: Your frontend gateway configuration must match your WooCommerce store settings:

<AccordionGroup>
  <Accordion title="Stripe Example">
    **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:**

    ```javascript theme={"system"}
    // Must use the SAME publishable key
    const stripe = Stripe('pk_live_abc123...'); // Same as store settings
    ```
  </Accordion>

  <Accordion title="PayPal Example">
    **WooCommerce Store Settings:**

    ```
    WooCommerce → Payments → PayPal
    - Client ID: your_paypal_client_id
    - Environment: live
    ```

    **Frontend Implementation:**

    ```javascript theme={"system"}
    // 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
      }
    });
    ```
  </Accordion>
</AccordionGroup>

### Rate Limiting for Checkout Operations

The checkout API includes enhanced rate limiting to prevent abuse:

```php theme={"system"}
// 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:

```php theme={"system"}
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

<AccordionGroup>
  <Accordion title="API Authentication">
    * **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
  </Accordion>

  <Accordion title="Customer Data Protection">
    * **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
  </Accordion>

  <Accordion title="Payment Security">
    * **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
  </Accordion>
</AccordionGroup>

### Performance

<AccordionGroup>
  <Accordion title="API Optimization">
    * **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
  </Accordion>

  <Accordion title="Client-Side Performance">
    * **Lazy load payment SDKs** to improve initial page load
    * **Implement progressive enhancement** for checkout forms
    * **Use efficient state management** to avoid unnecessary re-renders
    * **Optimize bundle size** by code splitting payment methods
    * **Implement proper loading states** during async operations
  </Accordion>
</AccordionGroup>

### User Experience

<AccordionGroup>
  <Accordion title="Form Design">
    * **Validate forms in real-time** but don't be overly aggressive
    * **Provide clear error messages** with actionable guidance
    * **Auto-format input fields** (card numbers, phone numbers, etc.)
    * **Support keyboard navigation** and screen readers
    * **Remember user preferences** for returning customers
  </Accordion>

  <Accordion title="Checkout Flow">
    * **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
  </Accordion>
</AccordionGroup>

### Development

<AccordionGroup>
  <Accordion title="Testing Strategy">
    * **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
  </Accordion>

  <Accordion title="Code Quality">
    * **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
  </Accordion>
</AccordionGroup>

### Consumer Key Management

<AccordionGroup>
  <Accordion title="Key Generation">
    * **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
  </Accordion>

  <Accordion title="Key Security">
    * **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
  </Accordion>

  <Accordion title="Key Monitoring">
    * **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
  </Accordion>
</AccordionGroup>

<Note>
  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.
</Note>
