ChatFi Pay

ChatFi Pay Docs

Accept Solana payments via API. Simple, fast, non-custodial.

What is ChatFi Pay?

ChatFi Pay lets you accept Solana payments from anyone — no bank, no signup, no middleman. Your customers get a simple payment page or QR code. You receive USDC or USDT directly to your wallet.

No technical knowledge needed to get started
Payments go directly to your Solana wallet
Share a link or QR code — works on any device
0.05% platform fee, only on confirmed payments

You don't need to write any code to use ChatFi Pay. Just follow these steps inside the ChatFi app:

1

Open the ChatFi App

Tap More at the bottom of the screen, then tap Payment Link.

2

Set Your Amount & Label

Enter how much you want to charge (or leave it blank for any amount), add a label like Invoice #001, and an optional note.

3

Generate & Share

Tap Generate Link. You'll get a payment page link and QR code. Share it via WhatsApp, email, or any platform — your customer opens it and pays instantly.

4

Track Payments

Go to More → Payment History to see all your paid and pending payments in one place.

Tip: You can also go to More → Merchant to set up a business name and webhook for automatic notifications when you get paid.
For Developers
1

Open ChatFi App

Go to More → Merchant in the ChatFi app.

2

Generate an API Key

Tap Generate API Key. Your key starts with cfp_. Keep it secret — it identifies your wallet.

3

Set a Webhook (optional)

Add a webhook URL to receive a POST request when a payment is confirmed.

Send a POST request to create a payment link your customers can pay via browser or wallet.

POSThttps://pay.chatfi.pro/api/payment

Headers

x-api-key: cfp_YOUR_KEY
Content-Type: application/json
Idempotency-Key: order-42        // optional -- retry-safe: a repeated request
                                  // with the same key returns the original
                                  // payment instead of creating a duplicate

Body

{
  "amount": 5,             // optional -- omit for open amount
  "token": "USDC",         // "USDC" | "USDT" -- defaults to USDC
  "label": "Invoice #001",
  "memo": "Payment for design work",  // optional
  "redirectUrl": "https://yoursite.com/thank-you",  // optional -- buyer is
                                                     // sent here after paying,
                                                     // with ?payment_id= and
                                                     // &status=paid appended
  "expiresInMinutes": 1440  // optional -- defaults to 1440 (24 hours)
}

Response

{
  "success": true,
  "id": "abc123",
  "checkToken": "a1b2c3d4...",  // safe to expose client-side for status
                                 // polling -- see "Check Payment Status" below
  "link": "https://pay.chatfi.pro/pay/abc123",
  "amount": 5.2,             // includes the 0.2 network-fee surcharge (USDC/USDT only)
  "requestedAmount": 5,      // what you originally asked for
  "feeUsdc": 0.2,
  "token": "USDC",
  "label": "Invoice #001",
  "status": "pending",
  "expiresAt": "2026-06-17T10:00:00.000Z"
}
GEThttps://pay.chatfi.pro/api/payment?id=PAYMENT_ID

Two ways to authenticate this call -- use whichever fits where the check is happening:

Option A -- your own backend (full access)

x-api-key: cfp_YOUR_KEY

Option B -- client-side polling (safe to expose in the browser)

GET https://pay.chatfi.pro/api/payment?id=abc123&checkToken=a1b2c3d4...

Use the checkToken returned when you created the payment. It can only ever read the status of that one payment -- it can't create payments, list your other payments, or act as your API key anywhere else. This is what you should ship to the browser for status polling, never your x-api-key.

Response

{
  "id": "abc123",
  "status": "completed",  // "pending" | "completed" | "expired"
  "amount": 5.2,
  "token": "USDC",
  "label": "Invoice #001",
  "paidAt": "2026-06-16T10:00:00.000Z",
  "txSignature": "5Fo8VJqG..."
}

ChatFi POSTs to your webhook URL when a payment is confirmed, and again if a payment expires unpaid.

payment.confirmed

{
  "event": "payment.confirmed",
  "id": "abc123",
  "amount": 5.2,
  "label": "Invoice #001",
  "memo": "Payment for design work",
  "walletAddress": "7tsf2T6S...",
  "txSignature": "5Fo8VJqG...",
  "paidAt": "2026-06-16T10:00:00.000Z"
}

payment.expired

Fired if a payment link is never paid before its expiresAt time (checked every 15 minutes).

{
  "event": "payment.expired",
  "id": "abc123",
  "amount": 5.2,
  "label": "Invoice #001",
  "walletAddress": "7tsf2T6S...",
  "expiredAt": "2026-06-17T10:00:00.000Z"
}

Verifying the signature

Every webhook request includes an X-ChatFi-Signature header: an HMAC-SHA256 hash of the raw request body, signed with your webhook secret (find it in the app under More → Merchant). Verify it before trusting the payload:

const crypto = require("crypto");

function isValidChatFiWebhook(rawBody, signatureHeader, webhookSecret) {
  const expected = crypto
    .createHmac("sha256", webhookSecret)
    .update(rawBody)
    .digest("hex");
  return signatureHeader === `sha256=${expected}`;
}

1. Create the payment on your backend

const res = await fetch("https://pay.chatfi.pro/api/payment", {
  method: "POST",
  headers: {
    "x-api-key": "cfp_YOUR_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 5,
    token: "USDC",
    label: "Order #42",
    memo: "T-shirt XL",
    redirectUrl: "https://yoursite.com/thank-you",
  }),
});

const { id, checkToken, link } = await res.json();
// Save id + checkToken against the order in your DB, then
// redirect customer to: link

2. Poll status from the browser -- safe to ship checkToken here

const res = await fetch(
  `https://pay.chatfi.pro/api/payment?id=${id}&checkToken=${checkToken}`
);
const { status } = await res.json();
// "pending" | "completed" | "expired"
0.05% platform fee is deducted from every confirmed payment.
For USDC/USDT payment links, a flat 0.2 stablecoin network-fee surcharge is added automatically on top of your requested amount — this covers the on-chain transfer cost and is paid by the customer, not deducted from your payout.

Payment links support USDC and USDT. Whichever token you set when creating the link is shown by default, but on the payment page your customer can manually switch between USDC and USDT before sending — either one will be detected and confirmed automatically.

Funds are swept directly to your wallet as soon as a payment is confirmed on-chain — ChatFi never holds custody of your funds at any point.

Found a bug, or have an idea to make ChatFi Pay better? We'd love to hear it.

Send Feedback

Powered by ChatFi · Built on Solana