Stablecoins

USDC and EUR-backed stablecoin payments with fiat settlement.

View as MarkdownInstall skills

VINR lets customers pay with regulated stablecoins — USDC and EURC — while you keep settling in plain fiat to your bank. You integrate stablecoins through the same payment object as cards; VINR handles the on-chain side, confirmation tracking, and the crypto-to-fiat conversion, so your accounting never has to touch a wallet.

Availability & currenciesAsk

Stablecoin acceptance is opt-in per account. Enable it under Settings → Payment methods in the Dashboard, or contact your account manager for higher-volume limits. Sandbox always has it enabled.

StablecoinSymbolNetworksSettles to
USD CoinUSDCEthereum, Base, PolygonYour fiat balance (FX applied)
Euro CoinEURCEthereum, BaseEUR balance (no FX)

A customer pays in the stablecoin; you are credited in your account's settlement currency (default EUR). When a customer pays USDC against a EUR-priced payment, VINR converts at the rate quoted at confirmation time and shows both legs on the payment.

Amounts are always set in your pricing currency using minor units — 1000 is €10.00. You never quote prices in tokens. VINR derives the on-chain amount from the live rate and locks it for the duration of the payment window.

How the flow worksAsk

customer picks USDC → VINR quotes token amount + address → customer sends on-chain
   → VINR watches for N confirmations → payment.completed → converted to fiat balance
  1. You create a payment as usual and send the customer to the hosted checkoutUrl.
  2. The customer selects a stablecoin and network. VINR shows a one-time deposit address, the exact token amount, and a countdown.
  3. The customer sends the funds from any wallet or exchange.
  4. VINR waits for the required network confirmations (the finality threshold), then converts to fiat and fires payment.completed.

Unlike cards, there is no separate authorization and capture step — an on-chain payment is captured the moment it reaches finality.

Creating a paymentAsk

Stablecoins use the standard create call. Optionally restrict the offered methods so the checkout shows only what you want.

import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const payment = await vinr.payments.create({
  amount: 5000,                 // €50.00 in minor units
  currency: 'EUR',
  description: 'Order #4471',
  paymentMethods: ['stablecoin'],
  stablecoin: {
    accept: ['USDC', 'EURC'],   // omit to accept all enabled tokens
    networks: ['base', 'ethereum'],
  },
  returnUrl: 'https://yoursite.com/payment/complete',
  metadata: { orderId: '4471' },
});

// payment.id          → "pay_3Nf8x2a..."
// payment.status      → "pending"
// payment.checkoutUrl → hosted page where the customer picks a token & network

While the payment is awaiting funds it stays pending. Once enough confirmations land, the status moves to completed and the conversion details appear under payment.stablecoin:

{
  "id": "pay_3Nf8x2a...",
  "status": "completed",
  "amount": 5000,
  "currency": "EUR",
  "stablecoin": {
    "token": "USDC",
    "network": "base",
    "tokenAmount": "54.12",
    "txHash": "0xab12...e9",
    "confirmations": 12,
    "fxRate": "0.9239"
  }
}

Listen for the result with a webhook rather than polling — on-chain timing is variable.

export async function POST(req: Request) {
  const payload = await req.text();
  const signature = req.headers.get('x-vinr-signature')!;
  const event = vinr.webhooks.verify(payload, signature);

  if (event.type === 'payment.completed') {
    fulfillOrder(event.data.metadata.orderId);
  }
  return new Response('ok', { status: 200 });
}

Settlement & timingAsk

Confirmation time depends on the network: low-fee chains like Base and Polygon typically reach finality in under a minute, while Ethereum mainnet can take several minutes during congestion. VINR only marks a payment completed after the finality threshold, so funds are final — there are no chargebacks on a confirmed stablecoin payment.

After conversion, funds land in your VINR balance in your settlement currency and pay out on your normal settlement schedule alongside card and bank revenue. FX spread and network handling fees are netted and itemized in reconciliation.

Stablecoin payments have an expiry window (default 30 minutes). If the customer underpays, overpays, or sends after the window closes, the payment will not auto-complete — see Limitations below.

Refunds & reversalsAsk

Refunds work through the standard refunds API. Because the original payment was converted to fiat, the refund is calculated in your pricing currency and sent back as stablecoin to a destination address.

const refund = await vinr.refunds.create({
  payment: 'pay_3Nf8x2a...',
  amount: 5000,                              // full or partial, in minor units
  stablecoin: { destinationAddress: '0xCustomerWallet...' },
});

// refund.id     → "re_8Kd2..."
// refund.status → "pending"  → "completed" once the on-chain transfer confirms

The refunded token amount is recomputed at the rate in effect when the refund is issued, so it may differ slightly from the tokens originally received. A destinationAddress is required — VINR cannot reverse an on-chain transfer back to its source automatically.

LimitationsAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page