# Stablecoins

> USDC and EUR-backed stablecoin payments with fiat settlement.

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 & currencies

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.

| Stablecoin | Symbol | Networks                | Settles to                     |
| ---------- | ------ | ----------------------- | ------------------------------ |
| USD Coin   | USDC   | Ethereum, Base, Polygon | Your fiat balance (FX applied) |
| Euro Coin  | EURC   | Ethereum, Base          | EUR 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 works

```
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 payment

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

```typescript
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`:

```json
{
  "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.

```typescript
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 & timing

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](/docs/operations/balances) in your settlement currency and pay out on your normal [settlement](/docs/operations/settlement) schedule alongside card and bank revenue. FX spread and network handling fees are netted and itemized in [reconciliation](/docs/operations/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 & reversals

Refunds work through the standard [refunds](/docs/payments/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.

```typescript
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.

## Limitations

#### Underpayments and overpayments

If the received amount does not match the quote, the payment stays `pending` and surfaces a `stablecoin.amount_mismatch` detail. Resolve it from the Dashboard by accepting the partial amount, refunding, or requesting a top-up.

#### Wrong network or token

Funds sent on an unsupported network or as an unsupported token are not credited automatically and may require manual recovery. Always send to the exact address, token, and network shown at checkout.

#### Expired payment window

Funds that arrive after the window closes are treated as a late deposit and held for manual review rather than auto-completing the order.

#### No partial captures or auth holds

Stablecoin payments are captured in full at finality. The [authorize and capture](/docs/payments/authorize-and-capture) flow is card-only.

## Next steps

[How payments work](/docs/payments/how-payments-work) — The shared object model behind every rail.

[Refunds](/docs/payments/payment-operations/refund) — Issue full and partial refunds across methods.

[Settlement](/docs/operations/settlement) — When and how converted funds reach your bank.
