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

# Implement ACP: Enable ChatGPT Instant Checkout Today

> Define three ACP tools, implement the matching endpoints, and register them with OpenAI so ChatGPT can complete purchases inside the conversation.

ACP (Agentic Commerce Protocol) is OpenAI's protocol for in-conversation commerce. Once you implement it, a ChatGPT user can search your catalog, review a purchase summary, and confirm an order without ever leaving the chat. The protocol works through OpenAI's function calling API: you define three tools, host the matching endpoints, and register the tools so ChatGPT knows how to invoke them.

## Prerequisites

Before you start, make sure you have:

* API endpoints you control on any stack
* A payment processor — Stripe is the most common choice for ACP; use Razorpay if you are targeting India
* A structured product catalog exposed through an API
* Basic familiarity with OpenAI function calling

## ACP tool definitions

You must define exactly three tools for ChatGPT to invoke: `search_products`, `initiate_checkout`, and `confirm_purchase`. Pass these definitions as JSON when registering with OpenAI.

```json Tool definitions theme={null}
[
  {
    "type": "function",
    "function": {
      "name": "search_products",
      "description": "Search the product catalog by keyword, category, or price range.",
      "parameters": {
        "type": "object",
        "properties": {
          "query": { "type": "string", "description": "Search keywords" },
          "category": { "type": "string", "description": "Product category" },
          "max_price": { "type": "number", "description": "Maximum price in dollars" }
        },
        "required": ["query"]
      }
    }
  },
  {
    "type": "function",
    "function": {
      "name": "initiate_checkout",
      "description": "Create a checkout session for selected products.",
      "parameters": {
        "type": "object",
        "properties": {
          "product_id": { "type": "string" },
          "variant_id": { "type": "string" },
          "quantity": { "type": "integer", "default": 1 }
        },
        "required": ["product_id", "quantity"]
      }
    }
  },
  {
    "type": "function",
    "function": {
      "name": "confirm_purchase",
      "description": "Confirm and complete a pending checkout session.",
      "parameters": {
        "type": "object",
        "properties": {
          "checkout_id": { "type": "string" },
          "payment_token": { "type": "string", "description": "Payment token from PSP" }
        },
        "required": ["checkout_id", "payment_token"]
      }
    }
  }
]
```

## Implement the tool endpoints

Each tool maps to one HTTP endpoint on your server. Implement all three before registering with OpenAI.

### `search_products`

<CodeGroup>
  ```javascript JavaScript theme={null}
  // POST /acp/tools/search_products
  app.post('/acp/tools/search_products', async (req, res) => {
    const { query, category, max_price } = req.body

    const products = await db.products.search({
      q: query,
      category,
      maxPrice: max_price ? max_price * 100 : undefined, // convert to cents
      availability: 'in_stock'
    })

    res.json({
      products: products.map(p => ({
        id: p.id,
        name: p.name,
        price: `$${(p.price_cents / 100).toFixed(2)}`,
        availability: p.availability,
        summary: p.description.slice(0, 200)
      }))
    })
  })
  ```

  ```typescript TypeScript theme={null}
  import { Request, Response } from 'express'

  // POST /acp/tools/search_products
  app.post('/acp/tools/search_products', async (req: Request, res: Response) => {
    const { query, category, max_price }: {
      query: string
      category?: string
      max_price?: number
    } = req.body

    const products = await db.products.search({
      q: query,
      category,
      maxPrice: max_price ? max_price * 100 : undefined,
      availability: 'in_stock'
    })

    res.json({
      products: products.map(p => ({
        id: p.id,
        name: p.name,
        price: `$${(p.price_cents / 100).toFixed(2)}`,
        availability: p.availability,
        summary: p.description.slice(0, 200)
      }))
    })
  })
  ```
</CodeGroup>

### `initiate_checkout`

<CodeGroup>
  ```javascript JavaScript theme={null}
  // POST /acp/tools/initiate_checkout
  app.post('/acp/tools/initiate_checkout', async (req, res) => {
    const { product_id, variant_id, quantity } = req.body

    const product = await db.products.get(product_id)
    const variant = variant_id ? await db.variants.get(variant_id) : null

    // Re-check availability
    if (product.availability !== 'in_stock') {
      return res.status(409).json({
        error: { code: 'out_of_stock', message: `${product.name} is no longer available.` }
      })
    }

    const checkout = await db.checkouts.create({
      product_id, variant_id, quantity,
      expires_at: new Date(Date.now() + 15 * 60 * 1000)
    })

    res.json({
      checkout_id: checkout.id,
      summary: {
        product: product.name,
        variant: variant?.label,
        quantity,
        subtotal: `$${((product.price_cents * quantity) / 100).toFixed(2)}`,
        expires_at: checkout.expires_at
      }
    })
  })
  ```

  ```typescript TypeScript theme={null}
  import { Request, Response } from 'express'

  // POST /acp/tools/initiate_checkout
  app.post('/acp/tools/initiate_checkout', async (req: Request, res: Response) => {
    const { product_id, variant_id, quantity }: {
      product_id: string
      variant_id?: string
      quantity: number
    } = req.body

    const product = await db.products.get(product_id)
    const variant = variant_id ? await db.variants.get(variant_id) : null

    if (product.availability !== 'in_stock') {
      return res.status(409).json({
        error: { code: 'out_of_stock', message: `${product.name} is no longer available.` }
      })
    }

    const checkout = await db.checkouts.create({
      product_id, variant_id, quantity,
      expires_at: new Date(Date.now() + 15 * 60 * 1000)
    })

    res.json({
      checkout_id: checkout.id,
      summary: {
        product: product.name,
        variant: variant?.label,
        quantity,
        subtotal: `$${((product.price_cents * quantity) / 100).toFixed(2)}`,
        expires_at: checkout.expires_at
      }
    })
  })
  ```
</CodeGroup>

### `confirm_purchase`

<CodeGroup>
  ```javascript JavaScript theme={null}
  // POST /acp/tools/confirm_purchase
  app.post('/acp/tools/confirm_purchase', async (req, res) => {
    const { checkout_id, payment_token } = req.body

    const checkout = await db.checkouts.get(checkout_id)
    if (!checkout || checkout.expires_at < new Date()) {
      return res.status(410).json({ error: { code: 'expired', message: 'Checkout session expired.' } })
    }

    const payment = await stripe.paymentIntents.create({
      amount: checkout.total_cents,
      currency: 'usd',
      payment_method: payment_token,
      confirm: true
    })

    const order = await db.orders.create({ checkout_id, payment_id: payment.id })

    res.json({
      order_id: order.id,
      status: 'confirmed',
      confirmation: `Order ${order.id} placed successfully.`,
      estimated_delivery: order.estimated_delivery
    })
  })
  ```

  ```typescript TypeScript theme={null}
  import { Request, Response } from 'express'

  // POST /acp/tools/confirm_purchase
  app.post('/acp/tools/confirm_purchase', async (req: Request, res: Response) => {
    const { checkout_id, payment_token }: {
      checkout_id: string
      payment_token: string
    } = req.body

    const checkout = await db.checkouts.get(checkout_id)
    if (!checkout || checkout.expires_at < new Date()) {
      return res.status(410).json({ error: { code: 'expired', message: 'Checkout session expired.' } })
    }

    const payment = await stripe.paymentIntents.create({
      amount: checkout.total_cents,
      currency: 'usd',
      payment_method: payment_token,
      confirm: true
    })

    const order = await db.orders.create({ checkout_id, payment_id: payment.id })

    res.json({
      order_id: order.id,
      status: 'confirmed',
      confirmation: `Order ${order.id} placed successfully.`,
      estimated_delivery: order.estimated_delivery
    })
  })
  ```
</CodeGroup>

## Register tools with OpenAI

Pass your tool definitions in the `tools` array when creating a chat completion. Set `tool_choice` to `"auto"` so the model decides when to invoke them.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import OpenAI from 'openai'

  const openai = new OpenAI()

  const response = await openai.chat.completions.create({
    model: 'gpt-4o',
    messages: [{ role: 'user', content: 'I want to buy running shoes under $150' }],
    tools: acpToolDefinitions, // the three tools defined above
    tool_choice: 'auto'
  })
  ```

  ```python Python theme={null}
  from openai import OpenAI

  client = OpenAI()

  response = client.chat.completions.create(
      model="gpt-4o",
      messages=[{"role": "user", "content": "I want to buy running shoes under $150"}],
      tools=acp_tool_definitions,
      tool_choice="auto"
  )
  ```
</CodeGroup>

## Test your implementation

Work through each scenario below before connecting to a live payment processor.

<Steps>
  <Step title="Test search">
    Start a conversation asking to find products. Confirm `search_products` is called with the correct parameters and returns properly shaped product data.
  </Step>

  <Step title="Test checkout initiation">
    After search results appear, ask to purchase one item. Confirm `initiate_checkout` is called and returns a valid checkout summary including `checkout_id` and `expires_at`.
  </Step>

  <Step title="Test purchase confirmation">
    Use a Stripe test token (`tok_visa`) to confirm the purchase. Verify `confirm_purchase` returns an `order_id` and `estimated_delivery`.
  </Step>

  <Step title="Test error recovery">
    Test with an out-of-stock product, an expired checkout session, and a declined payment. Verify error messages are human-readable and the agent responds to each state gracefully.
  </Step>
</Steps>

<Tip>
  Use the [ACP Validator](https://asva-ai.com/tools/acp-validator) to run automated checks against all three endpoints at once.
</Tip>

## Next steps

<CardGroup cols={2}>
  <Card title="ACP end-to-end implementation" icon="list-check" href="/acp/implementation">
    State machine, idempotency, and end-to-end validation checklist.
  </Card>

  <Card title="ACP tool endpoints reference" icon="plug" href="/acp/endpoints">
    Full endpoint schema, required fields, and response shapes.
  </Card>

  <Card title="ACP checkout: webhooks and going live" icon="shopping-cart" href="/acp/checkout-guide">
    Webhooks, idempotency middleware, and production go-live steps.
  </Card>

  <Card title="ACP instant checkout UX patterns" icon="bolt" href="/acp/instant-checkout">
    Conversation flows, failure states, and confirmation design.
  </Card>
</CardGroup>
