DEV Community

Vaultion
Vaultion

Posted on Originally published at vaultion.org AI-assisted

Accept USDT and USDC on a custom site without a payment processor account

Most ways to take crypto on a custom website start with a sign-up: create a processor account, pass business verification, generate an API key, store it somewhere safe, and let the processor collect your payments into a balance you withdraw later.

If you just want USDT and USDC paid to your own wallet, there's a lighter shape. This post walks through it with one server-side request and no API key.

The request

Your server creates a checkout with the price and the wallets you want to be paid in. escrow: 'off' means direct payments only:

// Server only. Browser calls from other sites are refused.
import { randomBytes } from 'node:crypto';

const res = await fetch('https://checkout.vaultion.org/v1/stores/sessions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    store: { url: 'https://yourshop.com', name: 'Your Shop' },
    orderRef: `order-${order.id}-${randomBytes(4).toString('hex')}`, // same ref = same checkout
    name: order.title,
    priceMinor: order.totalCents,          // US cents
    escrow: 'off',                         // direct payments only
    receiving: {
      evm: '0xYourEvmWallet',              // Base, Ethereum, Arbitrum, Polygon, BNB Smart Chain
      tron: 'TYourTronWallet',             // USDT and TRX on TRON
      solana: 'YourSolanaWallet',          // USDC, USDT and SOL on Solana
    },
    feePayer: 'merchant',                  // or 'buyer' to add the 0.75% fee on top
    returnUrl: `https://yourshop.com/orders/${order.id}`,
  }),
});
const { sessionId, checkoutPath } = await res.json();
// redirect the buyer to 'https://checkout.vaultion.org' + checkoutPath
Enter fullscreen mode Exit fullscreen mode

Store orderRef before redirecting: the same orderRef returns the same checkout, so a timed-out request is safe to retry. Keep the random part, so nobody can guess it and open that checkout first.

The buyer sees a hosted checkout with every network you sent an address for, and pays from their own wallet.

Where the money goes

On EVM networks, Solana and TRON, the buyer's wallet sends one transaction that pays your share to your address and the 0.75% fee to the fee address, both inside the same transaction. You're paid when it confirms, and there is no balance to withdraw.

Bitcoin and Litecoin work differently: a standard payment link names one address, so those payments go to a per-order deposit address and are forwarded to you after confirmation. That's a short period of custody, and it's worth knowing which of your coins work which way.

Marking the order paid

Read the status from your server:

const { status } = await fetch(
  `https://checkout.vaultion.org/v1/stores/sessions/${sessionId}`
).then((r) => r.json());

if (status === 'paid')     { /* confirmed on chain: fulfil the order */ }
if (status === 'reverted') { /* reversed by a chain reorganization: hold the order */ }
Enter fullscreen mode Exit fullscreen mode

A status changes only from a confirmed on-chain receipt. Don't mark an order paid because the buyer came back to your returnUrl or pasted a transaction hash: both are claims, not proof.

Optional: offer escrow on big orders

A confirmed crypto payment can't be charged back, which is good for you and a reason some buyers hesitate to pay a shop they don't know. Set escrow: 'choice' and the checkout offers both: pay directly, or pay into an escrow contract that holds the money until the buyer confirms delivery. The buyer pays the escrow fee (4% below 500 USDC, 3% from 500, 2% from 5,000), escrow is offered from $50, and disputes go to a Vaultion reviewer, which is not decentralized: you are trusting Vaultion's reviewers.

What to know first

  • Prices are in US dollars (priceMinor is US cents).
  • Call it from your server; browser calls from other origins are refused.
  • There's no sandbox and no webhooks yet: test with a small real payment and poll the status.
  • Only send addresses you control. A payment to a mistyped address can't be recovered.

Field reference, every status, and samples in Node, PHP and cURL: accept crypto payments with one API call. The same walkthrough, with the custody note for each coin, is on the site: accept USDC and USDT without a processor account.


Disclosure: I work on Vaultion, the API used here. This post was drafted with AI assistance.

Top comments (0)