Skip to content
Merged
Changes from 1 commit
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
310 changes: 173 additions & 137 deletions ecosystem/ton-pay/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,20 @@ Before installing and setting up the TON Pay SDK, the application must provide a
<Step
title="Add a payment button"
>
Add a `TonPayButton` and provide a handler. The handler uses `useTonPay` to connect a wallet if needed, send a transaction through TON Connect, and track the transaction result.
Add a `TonPayButton` and provide a handler. The handler uses `useTonPay` to connect a wallet if needed, send a transaction through TON Connect, and return tracking data for the next step.

- `TonPayButton` wraps wallet connect and disconnect UX and invokes the provided handler.
- `useTonPay` accepts an async message factory that receives `senderAddr` and returns `{ message }` along with any tracking fields to propagate.
- Return `reference` from `createTonPayTransfer` so it can be used later with `getTonPayTransferByReference`.

The returned `{ message }` is a TON Connect transaction message. `useTonPay` forwards it to the wallet through TON Connect and initiates the transaction send; direct calls to the wallet SDK are not required.

```tsx
import { TonPayButton, useTonPay } from "@ton-pay/ui-react";
import { useTonConnectUI } from "@tonconnect/ui-react";
import { createTonPayTransfer } from "@ton-pay/api";

export default function PayButton() {
const { pay } = useTonPay();
const [tonConnectUI] = useTonConnectUI();

async function createMessage(senderAddr: string) {
const { message, reference } = await createTonPayTransfer(
Expand All @@ -100,7 +99,7 @@ Before installing and setting up the TON Pay SDK, the application must provide a
},
{
chain: "testnet", // use "mainnet" for production
apiKey: "<TONPAY_API_KEY>" // optional
apiKey: "<TONPAY_API_KEY>", // optional
}
);
return { message, reference };
Expand All @@ -119,43 +118,39 @@ Before installing and setting up the TON Pay SDK, the application must provide a
Users can close the tab before transaction results are persisted, which breaks tracking and confirmation logic. Build messages and track transactions on the [server side](/ecosystem/ton-pay/payment-integration/payments-react).
</Aside>

<AccordionGroup

>
<AccordionGroup>
<Accordion
title="Minimal serverside flow quick sample"
title="Minimal server-side flow quick sample"
>
```ts
// Backend: POST /api/create-payment
import { createTonPayTransfer } from "@ton-pay/api";
import { TON } from "@ton-pay/api";
import { createTonPayTransfer, TON } from "@ton-pay/api";

app.post("/api/create-payment", async (req, res) => {
const { productId, senderAddr } = req.body;
const { productId, senderAddr } = req.body;

// Use the backend to create an order and calculate the amount using productId price
const amount = 12.23; // order amount
const orderId = 1; // ID of a new order
// Use the backend to create an order and calculate the amount using productId price
const amount = 12.23; // order amount
const orderId = 1; // ID of a new order

// 1) Create transfer + get tracking identifiers
const { message, reference, bodyBase64Hash } = await createTonPayTransfer(
{ amount, asset: TON, recipientAddr: "<WALLET_ADDRESS>", senderAddr },
{ chain: "testnet", apiKey: "<TONPAY_API_KEY>" } // API key is optional
);
// 1) Create transfer + get tracking identifiers
const { message, reference, bodyBase64Hash } = await createTonPayTransfer(
{ amount, asset: TON, recipientAddr: "<WALLET_ADDRESS>", senderAddr },
{ chain: "testnet", apiKey: "<TONPAY_API_KEY>" } // API key is optional
);

// 2) Persist identifiers the DB (orderId, reference, bodyBase64Hash) immediately
// 2) Persist identifiers in the DB (orderId, reference, bodyBase64Hash) immediately

// 3) Return only the message to the client
res.json({ message });
// 3) Return only the message to the client
res.json({ message });
});

```

```typescript
```tsx
// Frontend
import { TonPayButton, useTonPay } from "@ton-pay/ui-react";

export function PayOrder({ productId }: { productId: any }) {
export function PayOrder({ productId }: { productId: string }) {
const { pay } = useTonPay();

async function createMessage(senderAddr: string) {
Expand All @@ -175,98 +170,139 @@ Before installing and setting up the TON Pay SDK, the application must provide a
</AccordionGroup>

<Aside>
The TON Pay API key is optional. If available from the dashboard, pass it to `createTonPayTransfer` options to enable automatic tracking and webhook notifications.
The TON Pay API key is optional. If available from the dashboard, pass it to `createTonPayTransfer` options.
</Aside>
</Step>

<Step
title="Loading state and result handling"
>
Wallet approval does not mean the payment is finalized yet. After `pay(createMessage)` resolves, use the `reference` returned by `createTonPayTransfer` to query TON Pay until the transfer leaves the `pending` state.

Use the SDK flow below:

<AccordionGroup
1. Return `reference` from the `createMessage` function together with `message`.
1. Call `pay(createMessage)` and read the propagated `reference` from its resolved value.
1. Call `getTonPayTransferByReference(reference, options)` with the same `chain` and optional `apiKey` used during transfer creation.
1. While the SDK returns `status: "pending"`, keep the UI in a loading or "confirming payment" state.
1. When the status becomes `success`, show the confirmation UI and store `txHash`, `traceId`, and any other result fields needed by the application.
1. When the status becomes `error`, show the failure state and log `errorCode` or `errorMessage` for diagnostics.

Persist the `reference` as soon as it is available. If the user reloads the page or returns later, `reference` is the simplest way to resume status checks.

<Aside
type="note"
title="Production recommendation"
>
<Accordion
title="Loading state and result handling"
>
This example shows a minimal loading state and how to surface the reference. If a transaction hash is available, an explorer link can be rendered.
SDK polling is suitable for quick starts and simple client flows. For reliable order fulfillment, persist the `reference` on the server and combine client polling with [webhooks](/ecosystem/ton-pay/webhooks).
</Aside>

```tsx
import { useState } from "react";
import { TonPayButton, useTonPay } from "@ton-pay/ui-react";
import { createTonPayTransfer, getTonPayTransferByReference, type CompletedTonPayTransferInfo } from "@ton-pay/api";

export default function Checkout() {
const { pay } = useTonPay();
const [loading, setLoading] = useState(false);
const [reference, setReference] = useState<string | null>(null);
const [result, setResult] = useState<CompletedTonPayTransferInfo | null>(null);

const options = { chain: "testnet", apiKey: "yourTonPayApiKey" } as const; // API key is optional

async function createMessage(senderAddr: string) {
const { message, reference } = await createTonPayTransfer(
{ amount: 12.34, asset: "TON", recipientAddr: "EQC...yourWalletAddress", senderAddr },
options
);
setReference(reference);
return { message, reference };
}

async function handlePay() {
setLoading(true);
try {
const { reference } = await pay(createMessage);
// Poll status until success
for (;;) {
try {
const t = await getTonPayTransferByReference(reference, options);
if (t.status === "success") {
setResult(t);
break;
}
} catch {}
await new Promise(r => setTimeout(r, 1000));
}
} finally {
setLoading(false);
}
}

return (
<>
<TonPayButton handlePay={handlePay} isLoading={loading} />

{reference && !result && <div>Payment sent. Reference: {reference}</div>}
{result && <div>Payment successful! Tx hash: {result.txHash}</div>}
{/* If a transaction hash is available, render an explorer link:
<ExplorerLink txHash={result?.txHash!} />
*/}
</>
);
```tsx title="Result handling example" expandable
import { useState } from "react";
import { TonPayButton, useTonPay } from "@ton-pay/ui-react";
import {
createTonPayTransfer,
getTonPayTransferByReference,
type CompletedTonPayTransferInfo,
} from "@ton-pay/api";

type PaymentState = "idle" | "sending" | "pending" | "success" | "error";

const options = {
chain: "testnet",
apiKey: "<TONPAY_API_KEY>", // optional
} as const;

export default function Checkout() {
const { pay } = useTonPay();
const [paymentState, setPaymentState] = useState<PaymentState>("idle");
const [reference, setReference] = useState<string | null>(null);
const [result, setResult] = useState<CompletedTonPayTransferInfo | null>(null);
const [errorMessage, setErrorMessage] = useState<string | null>(null);

async function createMessage(senderAddr: string) {
const { message, reference } = await createTonPayTransfer(
{
amount: 12.34,
asset: "TON",
recipientAddr: "<WALLET_ADDRESS>",
senderAddr,
},
options
);

return { message, reference };
}

async function waitForTransferResult(reference: string) {
for (;;) {
const transfer = await getTonPayTransferByReference(reference, options);

if (transfer.status === "pending") {
await new Promise((resolve) => setTimeout(resolve, 1000));
continue;
}

return transfer;
}
```
}

```tsx
import { useTonWallet } from "@tonconnect/ui-react";
import { CHAIN } from "@tonconnect/ui";

function ExplorerLink({ txHash }: { txHash: string }) {
const wallet = useTonWallet();
const isTestnet = wallet?.account?.chain === CHAIN.TESTNET;
const tonviewer = isTestnet
? `https://testnet.tonviewer.com/transaction/${txHash}`
: `https://tonviewer.com/transaction/${txHash}`;
const tonscan = isTestnet
? `https://testnet.tonscan.org/tx/${txHash}`
: `https://tonscan.org/tx/${txHash}`;

return (
<div>
<a href={tonviewer} target="_blank" rel="noreferrer">TonViewer</a>
{" • "}
<a href={tonscan} target="_blank" rel="noreferrer">Tonscan</a>
</div>
);
async function handlePay() {
setPaymentState("sending");
setErrorMessage(null);
setResult(null);

try {
const { reference } = await pay(createMessage);
setReference(reference);
setPaymentState("pending");

const transfer = await waitForTransferResult(reference);

if (transfer.status === "success") {
setResult(transfer);
setPaymentState("success");
return;
}

setPaymentState("error");
setErrorMessage(transfer.errorMessage ?? "Payment failed");
} catch (error) {
setPaymentState("error");
setErrorMessage(error instanceof Error ? error.message : "Payment failed");
}
```
</Accordion>
</AccordionGroup>
}

return (
<>
<TonPayButton
handlePay={handlePay}
isLoading={paymentState === "sending" || paymentState === "pending"}
/>

{paymentState === "pending" && reference && (
<div>
Payment submitted. Waiting for blockchain confirmation. Reference: {reference}
</div>
)}

{paymentState === "success" && result && (
<div>
Payment confirmed. Tx hash: {result.txHash}
</div>
)}

{paymentState === "error" && errorMessage && (
<div>
Payment failed: {errorMessage}
</div>
)}
</>
);
}
```

See also: [Check status and retrieve info](/ecosystem/ton-pay/payment-integration/status-info).
</Step>
</Steps>

Expand All @@ -287,38 +323,38 @@ import { TonPayButton, useTonPay } from "@ton-pay/ui-react";
import { createTonPayTransfer } from "@ton-pay/api";

function AppContent() {
const { pay } = useTonPay();

async function createMessage(senderAddr: string) {
const { message, reference } = await createTonPayTransfer(
{
amount: 12.34,
asset: "TON",
recipientAddr: "<WALLET_ADDRESS>",
senderAddr,
commentToSender: "Order #123",
},
{
chain: "testnet",
apiKey: "<TONPAY_API_KEY>" // optional
}
);
return { message, reference };
}

return (
<TonPayButton handlePay={() => pay(createMessage)} />
const { pay } = useTonPay();

async function createMessage(senderAddr: string) {
const { message, reference } = await createTonPayTransfer(
{
amount: 12.34,
asset: "TON",
recipientAddr: "<WALLET_ADDRESS>",
senderAddr,
commentToSender: "Order #123",
},
{
chain: "testnet",
apiKey: "<TONPAY_API_KEY>", // optional
}
);
return { message, reference };
}

return (
<TonPayButton handlePay={() => pay(createMessage)} />
);
}

export default function App() {
return (
<TonConnectUIProvider
manifestUrl="https://ton-connect.github.io/demo-dapp-with-wallet/tonconnect-manifest.json"
>
<AppContent />
</TonConnectUIProvider>
);
return (
<TonConnectUIProvider
manifestUrl="https://ton-connect.github.io/demo-dapp-with-wallet/tonconnect-manifest.json"
>
<AppContent />
</TonConnectUIProvider>
);
}
```

Expand Down
Loading