Skip to content

Commit

Permalink
docs: Checkout polish (coinbase#1690)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xAlec authored Dec 6, 2024
1 parent f69950c commit 163efaf
Showing 1 changed file with 98 additions and 88 deletions.
186 changes: 98 additions & 88 deletions site/docs/pages/checkout/checkout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import App from '../../components/App';

# `<Checkout />`

The `Checkout` component provides a one-click checkout experience for onchain commerce.
The `Checkout` component provides a one-click checkout experience for onchain commerce - all for free.

Our all-in-one solution simplifies payment processing for onchain developers, removing complex integrations, high fees, and onboarding friction. Whether you're selling digital goods, services, or in-game items, this tool is for you.

Expand All @@ -20,12 +20,15 @@ Our all-in-one solution simplifies payment processing for onchain developers, re
- **Plug-and-Play Integration:** Add our `Checkout` button with just a few lines of code. No backend required.
- **Seamless Onboarding:** Support Passkey wallets to eliminate onboarding drop-offs.
- **Real-time Merchant Tooling:** Get instant payment tracking, analytics, and reporting.
- **Dynamic Payment Flows:** Generate charges on the fly, handle variable pricing, and pass in custom metadata.

## Prerequisites

Before using the `Checkout` component, ensure you've completed the [Getting Started](/getting-started) steps.

To use the `Checkout` component, you'll need to provide an API Key in `OnchainKitProvider`. You can get one following our [Getting Started](/getting-started#get-your-public-api-key) steps.
::::tip
To use the `Checkout` component, you'll need to provide a Client API Key in `OnchainKitProvider`. You can get one following our [Getting Started](/installation/nextjs#get-your-client-api-key) steps.
:::::

### Starting a new project

Expand Down Expand Up @@ -63,18 +66,15 @@ Wrap the `<OnchainKitProvider />` around your app, following the steps in [Getti

## Quickstart

### Option 1: Simple Product Checkout
Ideal for fixed-price items. Get started with minimal setup.

::::steps

### Sign up for a Coinbase Commerce account
<img alt="Create a product"
src="https://onchainkit.xyz/assets/commerce-1.png"
height="364"/>
Head to [Coinbase Commerce](https://beta.commerce.coinbase.com/) and sign up. This is where you’ll manage transactions, view reports, and configure payments.

### Create a product and copy the `productId`
<img alt="Copy productId"
src="https://onchainkit.xyz/assets/commerce-2.png"
height="364"/>
In the Coinbase Commerce dashboard, create a new product and copy the `productId`.

### Import the component
Expand All @@ -89,17 +89,44 @@ import { Checkout, CheckoutButton, CheckoutStatus } from '@coinbase/onchainkit/c
```
::::

### Option 2: Dynamic Charges
For variable pricing, custom metadata, or multi-product checkouts, use backend-generated charges.

::::steps

### Sign up for a Coinbase Commerce account
Head to [Coinbase Commerce](https://beta.commerce.coinbase.com/) and sign up. This is where you’ll manage transactions, view reports, and configure payments.

### Create a Coinbase Commerce API Key
In the [Coinbase Commerce dashboard](https://beta.commerce.coinbase.com/settings/security), create a new API Key under `Security` in `Settings`.

### Set up a backend to create charges dynamically using the Coinbase Commerce API.
See [Using chargeHandler](/checkout/checkout#using-chargehandler) for a code example.

### Pass the chargeID into Checkout via the chargeHandler prop.

```tsx
const chargeHandler = async () => {
const response = await fetch('/createCharge', { method: 'POST' });
const { id } = await response.json();
return id; // Return charge ID
};

<Checkout chargeHandler={chargeHandler}>
<CheckoutButton />
</Checkout>
```
::::

That's it! Starting selling onchain with just a few lines of code.

## Usage

### Configuring a checkout

You can create products on the Coinbase Commerce Portal and use them in the `Checkout` component through the `productId` prop.

If you'd like to create product metadata programmatically or implement a multi-product checkout, please see [Advanced Usage](/checkout/checkout#advanced-usage).
#### Using `productId`

Coinbase Commerce charges a [1% fee](https://help.coinbase.com/en/commerce/getting-started/fees) associated with all payments.
You can create products on the Coinbase Commerce Portal and use them in the `Checkout` component through the `productId` prop.

```tsx twoslash
import { Checkout, CheckoutButton } from '@coinbase/onchainkit/checkout';
Expand All @@ -121,6 +148,63 @@ export default function PayComponents() {
</Checkout>
</App>

#### Using `chargeHandler`

Alternatively, you can create charges dynamically using the Coinbase Commerce API [Create Charge](https://docs.cdp.coinbase.com/commerce-onchain/reference/creates-a-charge) endpoint by passing the chargeID into Checkout via the `chargeHandler` prop.

This function must have the signature `() => Promise<string>` and must return a valid chargeId created by the create charge endpoint.

:::tip
To create charges, you'll need a Coinbase Commerce [API Key](https://docs.cdp.coinbase.com/commerce-onchain/docs/getting-started).
:::

:::danger[⚠️ Warning]
You should protect your Coinbase Commerce API Key by only creating charges server-side.
:::

:::code-group
```ts [backend.ts]
// This backend endpoint should create a charge and return the response.
app.post('/createCharge', async (req: Request, res: Response) => {
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CC-Api-Key': 'your_api_key_here' // Replace this with your Coinbase Commerce API Key
},
body: JSON.stringify({
local_price: { amount: '1', currency: 'USDC' },
pricing_type: 'fixed_price',
metadata: { some_field: "some_value" } // Optional: Attach metadata like order ID or customer details
}),
};

const response = await fetch('https://api.commerce.coinbase.com/charges', options);
const data = await response.json();

res.json(data);
});

```

```tsx twoslash [frontend.tsx]
import { Checkout, CheckoutButton } from '@coinbase/onchainkit/checkout';

const chargeHandler = async () => {
const response = await fetch('https://your-backend.com/createCharge', { method: 'POST' });
const { id } = await response.json();
return id; // Return charge ID
};

<Checkout chargeHandler={chargeHandler}>
<CheckoutButton />
</Checkout>
```
:::

Note that `productId` and `chargeHandler` are mutually exclusive and only one can be provided as a prop to Checkout.

### Handling a successful checkout

To handle successful checkouts, use the `onStatus` prop to listen for the `success` callback.
Expand Down Expand Up @@ -163,8 +247,8 @@ const statusHandler = async (status: LifecycleStatus) => { // [!code focus]
</Checkout>
// ---cut-after---
```
:::tip[Coinbase Commerce API]
This is an authenticated endpoint. To verify charges, you'll need a Coinbase Commerce [API Key](https://docs.cdp.coinbase.com/commerce-onchain/docs/getting-started).
:::tip
To verify charges, you'll need a Coinbase Commerce [API Key](https://docs.cdp.coinbase.com/commerce-onchain/docs/getting-started).
:::

:::danger[⚠️ Warning]
Expand Down Expand Up @@ -313,80 +397,6 @@ export default function PayComponents() {

## Advanced Usage

### Shopping Carts and Multi-Product Checkout

You can accept payments for arbitrary product metadata using the Coinbase Commerce [create charge](https://docs.cdp.coinbase.com/commerce-onchain/reference/creates-a-charge) endpoint. This is useful if you have an existing inventory management system or want to implement custom features like multi-product checkouts, carts, etc.

:::tip[Coinbase Commerce API]
This is an authenticated endpoint. To create charges, you'll need a Coinbase Commerce [API Key](https://docs.cdp.coinbase.com/commerce-onchain/docs/getting-started).
:::

#### Example server side code

This Typescript example uses [Express](https://expressjs.com/) and [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

```tsx twoslash [server.ts]
import express, { Request, Response } from 'express';
const fetch = require('node-fetch');

const app = express();
const port = 3000;

app.use(express.json());

// ---cut-before---
// This endpoint should create a charge and return the response.
app.post('/createCharge', async (req: Request, res: Response) => {
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CC-Api-Key': 'your_api_key_here' // Replace this with your Coinbase Commerce API Key
}
};

const response = await fetch('https://api.commerce.coinbase.com/charges', options);
const data = await response.json();

res.json(data);
});
// ---cut-after---
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
```

:::danger[⚠️ Warning]
Charges should only be created server-side. If you create charges on the client, users will be able to create charges associated with your Commerce Merchant account.
:::

We expose a `chargeHandler` prop on the `Checkout` component which takes a callback that is invoked every time the Checkout button is clicked.

This function **must** have the signature `() => Promise<string>` and **must** return a valid `chargeId` created by the create charge endpoint.

Note that `productId` and `chargeHandler` are mutually exclusive and only one can be provided as a prop to `Checkout`.

```tsx twoslash
import { Checkout, CheckoutButton } from '@coinbase/onchainkit/checkout';


// ---cut-before---
const chargeHandler = async () => { // [!code focus]
// Create a charge on your backend server using the Create Charge API // [!code focus]
// Replace this URL with your backend endpoint // [!code focus]
const res = await fetch('api.merchant.com/createCharge'); // [!code focus]
const data = await res.json(); // [!code focus]
return data.id; // Return the chargeId // [!code focus]
} // [!code focus]

<Checkout chargeHandler={chargeHandler}> // [!code focus]
<CheckoutButton />
</Checkout>
// ---cut-after---
```


### Listening to the component lifecycle

You can use our Checkout [`LifecycleStatus`](/checkout/types#lifecyclestatus) and the `onStatus` prop to listen to transaction states.
Expand Down

0 comments on commit 163efaf

Please sign in to comment.