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

Commit

Permalink
Add webhooks and direct payments documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ianthirdweb committed Aug 5, 2024
1 parent 0bb3acb commit bc6284d
Show file tree
Hide file tree
Showing 4 changed files with 293 additions and 0 deletions.
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

0 comments on commit bc6284d

Please sign in to comment.