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

Commit bc6284d

Browse files
committed
Add webhooks and direct payments documentation
1 parent 0bb3acb commit bc6284d

File tree

4 files changed

+293
-0
lines changed

4 files changed

+293
-0
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { createMetadata, Callout, DocImage, Steps, Step } from "@doc";
2+
import DirectPaymentsFlow from "../assets/direct-payments-flow.png";
3+
4+
export const metadata = createMetadata({
5+
image: {
6+
title: "thirdweb Pay - Accept Direct Payments",
7+
icon: "thirdweb",
8+
},
9+
title: "thirdweb Pay - Accept Direct Payments | thirdweb",
10+
description:
11+
"Combine Pay and Engine to create a smooth point of sale experience on any chain",
12+
});
13+
14+
# Accept Direct Payments with Pay & Engine
15+
16+
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.
17+
18+
### Requirements
19+
20+
- [A thirdweb Client ID](https://thirdweb.com/dashboard/settings/api-keys)
21+
- [An Engine Instance](https://thirdweb.com/dashboard/engine)
22+
23+
### Purchase Flow Overview
24+
25+
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):
26+
27+
<DocImage src={DirectPaymentsFlow} />
28+
29+
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.
30+
E.g., `{ nftId: 1 }`.
31+
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.
32+
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.
33+
4. **Engine Executes the Transaction:** Engine backend wallet executes the transaction needed to deliver the token(s) to the user’s address.
34+
5. **(Optional) User Is Notified :** Your server confirms the completed Engine transaction and notifies the user.
35+
36+
Now, let's get started.
37+
38+
<Steps>
39+
<Step title="Set Up Thirdweb Engine">
40+
41+
1. If you haven't already, [deploy an Engine
42+
instance](https://thirdweb.com/dashboard/engine)
43+
44+
2. Create or import a backend wallet for Engine in [your Engine dashboard](https://thirdweb.com/dashboard/engine).
45+
46+
3. Send the required funds to the backend wallet
47+
* For example, if purchasing with Arb Nova USDC, then your backend wallet should hold this ERC20 token.
48+
* 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).
49+
* Your backend wallet should hold enough liquidity to handle any anticipated purchasing volume.
50+
51+
4. Make a plan to monitor and keep the float wallet topped up to avoid any issues with the service.
52+
</Step>
53+
<Step title="Integrate thirdweb Pay (Client)">
54+
1. [Integrate thirdweb Pay](https://portal.thirdweb.com/connect/pay/build-a-custom-experience) on the client side to enable fiat and crypto payments.
55+
56+
57+
2. Specify the required parameters for your Pay transaction.
58+
59+
```ts
60+
const quote = await getBuyWithFiatQuote({
61+
client: client, // thirdweb client
62+
fromCurrencySymbol: "USD", // fiat currency symbol
63+
toChainId: arbnova.id, // arbitrum nova chain id
64+
toAmount: "100", // amount of token to buy
65+
toTokenAddress: USDC_TOKEN_ADDRESS, // address of payment token
66+
fromAddress: "<USERS_WALLET_ADDRESS>",
67+
toAddress: "<YOUR_WALLET_ADDRESS>",
68+
purchaseData: {
69+
nftId: 1
70+
}
71+
});
72+
```
73+
74+
|Parameter|Type|Description|
75+
|----|--|--|
76+
|fromCurrencySymbol|`string`|The fiat currency symbol you'd like to accept (currently limited to USD and EUR) |
77+
|toChainId|`string`|[Chain ID](https://thirdweb.com/chainlist) for the destination token.|
78+
|toTokenAddress|`string`|Address of the destination token.|
79+
|toAmount|`string`|The price of the asset denominated in your desination token.|
80+
|fromAddress|`string`|The user's wallet address.|
81+
|toAddress|`string`|The wallet you'd like funds to be sent to. This can be your business wallet or an Engine backend wallet. |
82+
|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 }` |
83+
84+
</Step>
85+
<Step title="Integrate thirdweb Pay (Server)">
86+
1. Create a “Purchase Complete” webhook in [the Pay dashboard](https://thirdweb.com/dashboard/connect/pay).
87+
2. The [Pay webhook POST response](/connect/pay/webhooks#purchase-complete) will include the BuyWithCryptoStatus or BuyWithFiatStatus in the body.
88+
* This will also include the purchaseData you previously passed (metadata identifying the customer information, etc.).
89+
* A request will be sent on every status change.
90+
3. Listen for [completed purchase statuses](https://portal.thirdweb.com/connect/pay/build-a-custom-experience#Poll%20for%20Transaction%20Status).
91+
* Note, if this is a two-step BuyWithFiat transaction (onramp, then swap), you should also listen for `CRYPTO_SWAP_COMPLETED`
92+
4. When a purchase is completed, determine the purchaser, order and validate the amounts.
93+
- The fromAddress in the status will show purchasing address
94+
- The purchaseData will contain more information you previously for the purchase details
95+
- Validate the information. For example, 100 USDC was sent to your wallet.
96+
5. Send a contract call to Engine for the float wallet to purchase the item
97+
- For example, send a transaction to the float wallet for `mintTo(fromAddress)`
98+
- 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
99+
6. Confirm the purchase was successful.
100+
</Step>
101+
</Steps>
102+
103+
Once you've completed all of these steps, you'll be ready to offer a great purchase UX for your users.
Loading

src/app/connect/pay/webhooks/page.mdx

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import { createMetadata, DocImage } from "@doc";
2+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
3+
4+
export const metadata = createMetadata({
5+
title: "Webhooks | thirdweb Pay",
6+
description:
7+
"Configure Pay webhooks to get notified at any point during a transaction's lifecycle.",
8+
});
9+
10+
# Webhooks
11+
12+
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).
13+
14+
## Events
15+
16+
To listen to events, create a webhook in [the Pay dashboard](https://thirdweb.com/dashboard/connect/pay). Webhook URLs must start with `https://`.
17+
18+
| Event | Description |
19+
| ------------------- | ----------------------------------- |
20+
| `purchase_complete` | A transaction is confirmed onchain. |
21+
22+
### Purchase Complete
23+
24+
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.
25+
26+
Example Response:
27+
28+
<Tabs defaultValue="fiat">
29+
30+
<TabsList>
31+
<TabsTrigger value="fiat">Fiat Purchase</TabsTrigger>
32+
<TabsTrigger value="crypto">Crypto Purchase</TabsTrigger>
33+
</TabsList>
34+
35+
<TabsContent value='fiat'>
36+
```json
37+
{
38+
"data": {
39+
"buyWithFiatStatus": {
40+
"intentId": "f4cf8ab7-bb62-4b3b-a180-70fc7d72446c",
41+
"status": "ON_RAMP_TRANSFER_COMPLETED",
42+
"toAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
43+
"quote": {
44+
"createdAt": "2024-06-18T23:46:46.024Z",
45+
"fromCurrency": {
46+
"amountUnits": "279",
47+
"amount": "2.79",
48+
"currencySymbol": "USD",
49+
"decimals": 2,
50+
"amountUSDCents": 279
51+
},
52+
"fromCurrencyWithFees": {
53+
"amountUnits": "294",
54+
"amount": "2.94",
55+
"currencySymbol": "USD",
56+
"decimals": 2,
57+
"amountUSDCents": 279
58+
},
59+
"onRampToken": {
60+
"chainId": 137,
61+
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
62+
"name": "Matic",
63+
"symbol": "MATIC",
64+
"decimals": 18,
65+
"priceUSDCents": 54.797200000000004
66+
},
67+
"toToken": {
68+
"chainId": 137,
69+
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
70+
"name": "Matic",
71+
"symbol": "MATIC",
72+
"decimals": 18,
73+
"priceUSDCents": 54.797200000000004
74+
},
75+
"estimatedOnRampAmountWei": "5000000000000000000",
76+
"estimatedOnRampAmount": "5",
77+
"estimatedToTokenAmount": "5",
78+
"estimatedToTokenAmountWei": "5000000000000000000",
79+
"estimatedDurationSeconds": 30
80+
},
81+
"source": {
82+
"completedAt": "2024-06-18T23:49:00.347Z",
83+
"amount": "5",
84+
"amountWei": "5000000000000000000",
85+
"token": {
86+
"chainId": 137,
87+
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
88+
"name": "Matic",
89+
"symbol": "MATIC",
90+
"decimals": 18,
91+
"priceUSDCents": 54.797200000000004
92+
},
93+
"transactionHash": "0x4bb089f6a60b49235a817b52bf39bc078f1246df15731b85837526bb62cf4e70",
94+
"explorerLink": "https://polygonscan.com/tx/0x4bb089f6a60b49235a817b52bf39bc078f1246df15731b85837526bb62cf4e70",
95+
"amountUSDCents": 275
96+
}
97+
}
98+
}
99+
}
100+
```
101+
</TabsContent>
102+
103+
<TabsContent value='crypto'>
104+
```json
105+
{
106+
"data": {
107+
"buyWithCryptoStatus": {
108+
"swapType": "SAME_CHAIN",
109+
"source": {
110+
"transactionHash": "0x74d6c619a09e78f03f4bd495f29d5937a2539d0bbe8973e7710dce3e88c30b8b",
111+
"token": {
112+
"chainId": 10,
113+
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
114+
"decimals": 18,
115+
"name": "ETH",
116+
"symbol": "ETH",
117+
"priceUSDCents": 346529
118+
},
119+
"amountWei": "318486512146714",
120+
"amount": "0.000318486512146714",
121+
"amountUSDCents": 110,
122+
"completedAt": "2024-06-18T23:44:07.000Z"
123+
},
124+
"status": "COMPLETED",
125+
"subStatus": "SUCCESS",
126+
"fromAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
127+
"toAddress": "0xebfb127320fcbe8e07e5a03a4bfb782219f4735b",
128+
"quote": {
129+
"fromToken": {
130+
"chainId": 10,
131+
"tokenAddress": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
132+
"decimals": 18,
133+
"name": "ETH",
134+
"symbol": "ETH",
135+
"priceUSDCents": 346529
136+
},
137+
"toToken": {
138+
"chainId": 10,
139+
"tokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
140+
"decimals": 6,
141+
"name": "USD Coin",
142+
"symbol": "USDC",
143+
"priceUSDCents": 99
144+
},
145+
"fromAmountWei": "318486512146714",
146+
"fromAmount": "0.000318486512146714",
147+
"toAmountWei": "1100000",
148+
"toAmount": "1.1",
149+
"toAmountMinWei": "1100000",
150+
"toAmountMin": "1.1",
151+
"estimated": {
152+
"fromAmountUSDCents": 110,
153+
"toAmountMinUSDCents": 109,
154+
"toAmountUSDCents": 109,
155+
"slippageBPS": 91,
156+
"feesUSDCents": 32,
157+
"gasCostUSDCents": 40,
158+
"durationSeconds": 30
159+
},
160+
"createdAt": "2024-06-18T23:43:45.900Z"
161+
},
162+
"destination": {
163+
"transactionHash": "0x74d6c619a09e78f03f4bd495f29d5937a2539d0bbe8973e7710dce3e88c30b8b",
164+
"token": {
165+
"chainId": 10,
166+
"tokenAddress": "0x0b2c639c533813f4aa9d7837caf62653d097ff85",
167+
"decimals": 6,
168+
"name": "USD Coin",
169+
"symbol": "USDC",
170+
"priceUSDCents": 99
171+
},
172+
"amountWei": "1100000",
173+
"amount": "1.1",
174+
"amountUSDCents": 109,
175+
"completedAt": "2024-06-18T23:44:07.000Z"
176+
}
177+
}
178+
}
179+
}
180+
```
181+
</TabsContent>
182+
</Tabs>

src/app/connect/sidebar.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ export const sidebar: SideBar = {
482482
},
483483
],
484484
},
485+
{
486+
name: "Webhooks",
487+
href: `${paySlug}/webhooks`,
488+
},
485489
{
486490
name: "Enable Test Mode",
487491
href: `${paySlug}/test-mode`,
@@ -490,6 +494,10 @@ export const sidebar: SideBar = {
490494
name: "Build a Custom Experience",
491495
href: `${paySlug}/build-a-custom-experience`,
492496
},
497+
{
498+
name: "Accept Direct Payments",
499+
href: `${paySlug}/accept-direct-payments`,
500+
},
493501
{
494502
name: "FAQs",
495503
href: `${paySlug}/faqs`,

0 commit comments

Comments
 (0)