Skip to content
This repository has been archived by the owner on Aug 5, 2024. It is now read-only.

Add webhooks and direct payments documentation #552

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions src/app/connect/pay/accept-direct-payments/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { createMetadata, Callout, DocImage, Steps, Step } from "@doc";
import DirectPaymentsFlow from "../assets/direct-payments-flow.png";

export const metadata = createMetadata({
image: {
title: "thirdweb Pay - Accept Direct Payments",
icon: "thirdweb",
},
title: "thirdweb Pay - Accept Direct Payments | thirdweb",
description:
"Combine Pay and Engine to create a smooth point of sale experience on any chain",
});

# Accept Direct Payments with Pay & Engine

Learn how to accept fiat and crypto from your customers with Pay and trigger Engine actions, like minting NFTs or transferring tokens to user wallets.

### Requirements

- [A thirdweb Client ID](https://thirdweb.com/dashboard/settings/api-keys)
- [An Engine Instance](https://thirdweb.com/dashboard/engine)

### Purchase Flow Overview

Before jumping in, it's important to understand the full system, from initial purchase to the eventual transfer of assets. This is a four step process (with an optional fifth):

<DocImage src={DirectPaymentsFlow} />

1. **User Initiates Purchase:** User sends specified funds (ETH, MATIC, USD, etc.) to your backend wallet via thirdweb Pay. Use the `purchaseData` field to pass any item data needed in the webhook.
E.g., `{ nftId: 1 }`.
2. **Pay Processes Purchase:** thirdweb Pay processes the transaction and sends a [Purchase Complete webhook](/connect/pay/webhooks#purchase-complete) to your dapp’s server when the transaction is complete.
3. **Your Server Calls Engine:** Your server processes the webhook and sends a contract call to the thirdweb Engine backend wallet to perform the item purchase.
4. **Engine Executes the Transaction:** Engine backend wallet executes the transaction needed to deliver the token(s) to the user’s address.
5. **(Optional) User Is Notified :** Your server confirms the completed Engine transaction and notifies the user.

Now, let's get started.

<Steps>
<Step title="Set Up Thirdweb Engine">

1. If you haven't already, [deploy an Engine
instance](https://thirdweb.com/dashboard/engine)

2. Create or import a backend wallet for Engine in [your Engine dashboard](https://thirdweb.com/dashboard/engine).

3. Send the required funds to the backend wallet
* For example, if purchasing with Arb Nova USDC, then your backend wallet should hold this ERC20 token.
* If your backend wallet holds an ERC20 token, ensure to add a native token balance as well to cover gas costs. For example, for a transaction on Arbitrum Nova, your backend wallet should hold both Arb Nova USDC (for payment) and Arb Nova ETH (for gas).
* Your backend wallet should hold enough liquidity to handle any anticipated purchasing volume.

4. Make a plan to monitor and keep the float wallet topped up to avoid any issues with the service.
</Step>
<Step title="Integrate thirdweb Pay (Client)">
1. [Integrate thirdweb Pay](https://portal.thirdweb.com/connect/pay/build-a-custom-experience) on the client side to enable fiat and crypto payments.


2. Specify the required parameters for your Pay transaction.

```ts
const quote = await getBuyWithFiatQuote({
client: client, // thirdweb client
fromCurrencySymbol: "USD", // fiat currency symbol
toChainId: arbnova.id, // arbitrum nova chain id
toAmount: "100", // amount of token to buy
toTokenAddress: USDC_TOKEN_ADDRESS, // address of payment token
fromAddress: "<USERS_WALLET_ADDRESS>",
toAddress: "<YOUR_WALLET_ADDRESS>",
purchaseData: {
nftId: 1
}
});
```

|Parameter|Type|Description|
|----|--|--|
|fromCurrencySymbol|`string`|The fiat currency symbol you'd like to accept (currently limited to USD and EUR) |
|toChainId|`string`|[Chain ID](https://thirdweb.com/chainlist) for the destination token.|
|toTokenAddress|`string`|Address of the destination token.|
|toAmount|`string`|The price of the asset denominated in your desination token.|
|fromAddress|`string`|The user's wallet address.|
|toAddress|`string`|The wallet you'd like funds to be sent to. This can be your business wallet or an Engine backend wallet. |
|purchaseData|`Object`|Any details you need to pass in order to track your transaction. If this is a secondary sale, you may want to include details like `{ nftId: 1, orderId: 1 }` |

</Step>
<Step title="Integrate thirdweb Pay (Server)">
1. Create a “Purchase Complete” webhook in [the Pay dashboard](https://thirdweb.com/dashboard/connect/pay).
2. The [Pay webhook POST response](/connect/pay/webhooks#purchase-complete) will include the BuyWithCryptoStatus or BuyWithFiatStatus in the body.
* This will also include the purchaseData you previously passed (metadata identifying the customer information, etc.).
* A request will be sent on every status change.
3. Listen for [completed purchase statuses](https://portal.thirdweb.com/connect/pay/build-a-custom-experience#Poll%20for%20Transaction%20Status).
* Note, if this is a two-step BuyWithFiat transaction (onramp, then swap), you should also listen for `CRYPTO_SWAP_COMPLETED`
4. When a purchase is completed, determine the purchaser, order and validate the amounts.
- The fromAddress in the status will show purchasing address
- The purchaseData will contain more information you previously for the purchase details
- Validate the information. For example, 100 USDC was sent to your wallet.
5. Send a contract call to Engine for the float wallet to purchase the item
- For example, send a transaction to the float wallet for `mintTo(fromAddress)`
- For secondary purchases, like a marketplace direct listing, you can use the appropriate Engine endpoint, passing the ultimate recipient of the NFT as the buyer
6. Confirm the purchase was successful.
</Step>
</Steps>

Once you've completed all of these steps, you'll be ready to offer a great purchase UX for your users.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
182 changes: 182 additions & 0 deletions src/app/connect/pay/webhooks/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { createMetadata, DocImage } from "@doc";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";

export const metadata = createMetadata({
title: "Webhooks | thirdweb Pay",
description:
"Configure Pay webhooks to get notified at any point during a transaction's lifecycle.",
});

# Webhooks

Pay can be configured to send webhook events to notify your application any time an event happens on your transaction. Pay sends a response, via a HTTP request, to any endpoint URLs that you have provided us in [the Pay dashboard](https://thirdweb.com/dashboard/connect/pay).

## Events

To listen to events, create a webhook in [the Pay dashboard](https://thirdweb.com/dashboard/connect/pay). Webhook URLs must start with `https://`.

| Event | Description |
| ------------------- | ----------------------------------- |
| `purchase_complete` | A transaction is confirmed onchain. |

### Purchase Complete

Triggered when a transaction is confirmed onchain. This event provides information about the new status of the order and its transactionHash, as well as other relevant information.

Example Response:

<Tabs defaultValue="fiat">

<TabsList>
<TabsTrigger value="fiat">Fiat Purchase</TabsTrigger>
<TabsTrigger value="crypto">Crypto Purchase</TabsTrigger>
</TabsList>

<TabsContent value='fiat'>
```json
{
"data": {
"buyWithFiatStatus": {
"intentId": "f4cf8ab7-bb62-4b3b-a180-70fc7d72446c",
"status": "ON_RAMP_TRANSFER_COMPLETED",
"toAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
"quote": {
"createdAt": "2024-06-18T23:46:46.024Z",
"fromCurrency": {
"amountUnits": "279",
"amount": "2.79",
"currencySymbol": "USD",
"decimals": 2,
"amountUSDCents": 279
},
"fromCurrencyWithFees": {
"amountUnits": "294",
"amount": "2.94",
"currencySymbol": "USD",
"decimals": 2,
"amountUSDCents": 279
},
"onRampToken": {
"chainId": 137,
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"name": "Matic",
"symbol": "MATIC",
"decimals": 18,
"priceUSDCents": 54.797200000000004
},
"toToken": {
"chainId": 137,
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"name": "Matic",
"symbol": "MATIC",
"decimals": 18,
"priceUSDCents": 54.797200000000004
},
"estimatedOnRampAmountWei": "5000000000000000000",
"estimatedOnRampAmount": "5",
"estimatedToTokenAmount": "5",
"estimatedToTokenAmountWei": "5000000000000000000",
"estimatedDurationSeconds": 30
},
"source": {
"completedAt": "2024-06-18T23:49:00.347Z",
"amount": "5",
"amountWei": "5000000000000000000",
"token": {
"chainId": 137,
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"name": "Matic",
"symbol": "MATIC",
"decimals": 18,
"priceUSDCents": 54.797200000000004
},
"transactionHash": "0x4bb089f6a60b49235a817b52bf39bc078f1246df15731b85837526bb62cf4e70",
"explorerLink": "https://polygonscan.com/tx/0x4bb089f6a60b49235a817b52bf39bc078f1246df15731b85837526bb62cf4e70",
"amountUSDCents": 275
}
}
}
}
```
</TabsContent>

<TabsContent value='crypto'>
```json
{
"data": {
"buyWithCryptoStatus": {
"swapType": "SAME_CHAIN",
"source": {
"transactionHash": "0x74d6c619a09e78f03f4bd495f29d5937a2539d0bbe8973e7710dce3e88c30b8b",
"token": {
"chainId": 10,
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"decimals": 18,
"name": "ETH",
"symbol": "ETH",
"priceUSDCents": 346529
},
"amountWei": "318486512146714",
"amount": "0.000318486512146714",
"amountUSDCents": 110,
"completedAt": "2024-06-18T23:44:07.000Z"
},
"status": "COMPLETED",
"subStatus": "SUCCESS",
"fromAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
"toAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
"quote": {
"fromToken": {
"chainId": 10,
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"decimals": 18,
"name": "ETH",
"symbol": "ETH",
"priceUSDCents": 346529
},
"toToken": {
"chainId": 10,
"tokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
"decimals": 6,
"name": "USD Coin",
"symbol": "USDC",
"priceUSDCents": 99
},
"fromAmountWei": "318486512146714",
"fromAmount": "0.000318486512146714",
"toAmountWei": "1100000",
"toAmount": "1.1",
"toAmountMinWei": "1100000",
"toAmountMin": "1.1",
"estimated": {
"fromAmountUSDCents": 110,
"toAmountMinUSDCents": 109,
"toAmountUSDCents": 109,
"slippageBPS": 91,
"feesUSDCents": 32,
"gasCostUSDCents": 40,
"durationSeconds": 30
},
"createdAt": "2024-06-18T23:43:45.900Z"
},
"destination": {
"transactionHash": "0x74d6c619a09e78f03f4bd495f29d5937a2539d0bbe8973e7710dce3e88c30b8b",
"token": {
"chainId": 10,
"tokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
"decimals": 6,
"name": "USD Coin",
"symbol": "USDC",
"priceUSDCents": 99
},
"amountWei": "1100000",
"amount": "1.1",
"amountUSDCents": 109,
"completedAt": "2024-06-18T23:44:07.000Z"
}
}
}
}
```
</TabsContent>
</Tabs>
8 changes: 8 additions & 0 deletions src/app/connect/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,10 @@ export const sidebar: SideBar = {
},
],
},
{
name: "Webhooks",
href: `${paySlug}/webhooks`,
},
{
name: "Enable Test Mode",
href: `${paySlug}/test-mode`,
Expand All @@ -490,6 +494,10 @@ export const sidebar: SideBar = {
name: "Build a Custom Experience",
href: `${paySlug}/build-a-custom-experience`,
},
{
name: "Accept Direct Payments",
href: `${paySlug}/accept-direct-payments`,
},
{
name: "FAQs",
href: `${paySlug}/faqs`,
Expand Down