Integrate payment component natively in your platform and start accepting SOL and SPL token payments, seamlessly!
npm install @candypay/elements @candypay/checkout-sdk
- First, wrap your app in the
CheckoutProvider
component as shown below:
import { CheckoutProvider } from "@candypay/elements";
import { AppProps } from "next/app";
const App = ({ Component, pageProps }: AppProps) => {
return (
<CheckoutProvider
network="mainnet" // or "devnet"
>
<Component {...pageProps} />
</CheckoutProvider>
);
};
export default App;
- Using the
PayElement
component:
import { CreateIntentResponse } from "@candypay/checkout-sdk";
import axios from "axios";
import { PayElement } from "@candypay/elements";
import { toast } from "react-hot-toast";
export default function Web() {
const intentHandler = async (): Promise<CreateIntentResponse> => {
const res = await axios.post("/api/intent/create");
return res.data;
};
return (
<>
<PayElement
intentHandler={intentHandler}
onSuccess={() => {
console.log("success");
toast.success("Payment successful");
}}
onError={() => {
console.log("error");
toast.error("Payment failed");
}}
/>
</>
);
}
- API Handler to create the intent (using the
checkout-sdk
):
- lib/init/candypay.ts
import { CandyPay } from "@candypay/checkout-sdk";
const candypay = new CandyPay({
api_keys: {
public_api_key: process.env[`NEXT_PUBLIC_CP_API`] as string,
private_api_key: process.env[`CANDYPAY_PRIVATE_KEY`] as string,
},
network: "mainnet",
config: {
collect_shipping_address: false,
},
});
export { candypay };
pages/api/intent/create.ts
import { NextApiHandler } from "next";
import { candypay } from "../../../lib/init/candypay";
const handler: NextApiHandler = async (req, res) => {
if (req.method !== "POST") {
res.status(405).end();
return;
}
const response = await candypay.paymentIntent.create({
tokens: ["shdw", "bonk"],
items: [
{
name: "Nike Air Force",
image:
"https://static.nike.com/a/images/t_PDP_864_v1/f_auto,b_rgb:f5f5f5/b7d9211c-26e7-431a-ac24-b0540fb3c00f/air-force-1-07-shoes-WrLlWX.png",
price: 0.1,
quantity: 1,
},
],
});
return res.status(200).json(response);
};
export default handler;
In the above example, candypay
is an instance of the CandyPay
class from the checkout-sdk
package. The paymentIntent.create
method returns a CreateIntentResponse
object, which is used by the PayElement
component to render the payment form.
Prop | Type | Description |
---|---|---|
intentHandler | () => Promise<CreateIntentResponse> |
A function that returns a CreateIntentResponse object. This is used to create the payment intent. |
onSuccess | () => void |
A function that is called when the payment is successful. |
onError | () => void |
A function that is called when the payment fails. |
theme | Theme |
Primary and secondary colors to be used for the component. |
Example theme object:
const theme = {
primaryColor: "#ff0000",
secondaryColor: "#0000ff",
};
The onSuccess
prop is called when the payment is successful. It is passed an object with the following params:
{
customer: string; // the public key of the customer in string format
signature: string; // signature of the transaction
}
<PayElement
intentHandler={intentHandler}
onSuccess={(d: SuccessResponse) => {
console.log(d.signature);
toast.success("Payment successful");
}}
onError={() => {
console.log("error");
toast.error("Payment failed");
}}
/>
In the above example, SuccessResponse
is a type imported from the sdk like so:
import { SuccessResponse } from "@candypay/elements";
If you're using js, you can ignore assigning the type to the onSuccess
prop.
NOTE: If you're using Vercel serverless functions then the initial API request might take a while because of the cold start.