Next.js에서 비트코인 결제 받기 — 5분 가이드

발행: (2026년 2월 13일 오전 09:09 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

위에 제공된 내용만으로는 번역할 텍스트가 없습니다. 번역을 원하는 본문을 제공해 주시면 한국어로 번역해 드리겠습니다.

개요

제3자 보관, KYC 서류, 긴 승인 절차 없이 Next.js 앱에서 암호화폐 결제를 받으세요. @profullstack/coinpay 를 설치하면 BTC, ETH, SOL, POL, BCH, USDC 등 다양한 암호화폐를 직접 제어하는 지갑으로 직접 받을 수 있습니다.

  • 비보관형 – 개인 키가 서버를 떠나지 않습니다
  • 6개 체인 – BTC, ETH, SOL, POL, BCH, USDC
  • HD 지갑 파생 – 결제당 고유 주소 제공
  • 자동 USD 환산율
  • 결제 확인 시 웹훅 알림

설치

npm install @profullstack/coinpay

서버‑사이드 API 라우트

import { NextRequest, NextResponse } from 'next/server';

const COINPAY_API = 'https://coinpayportal.com/api';
const API_KEY = process.env.COINPAY_API_KEY!;

export async function POST(req: NextRequest) {
  const { amount, currency, metadata } = await req.json();

  const res = await fetch(`${COINPAY_API}/payments`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${API_KEY}`,
    },
    body: JSON.stringify({
      amount,          // amount in USD
      currency,        // 'BTC', 'ETH', 'SOL', 'POL', 'BCH', 'USDC'
      metadata,        // your order ID, user info, etc.
      webhook_url: `${process.env.NEXT_PUBLIC_BASE_URL}/api/webhooks/coinpay`,
    }),
  });

  const payment = await res.json();

  return NextResponse.json({
    paymentId: payment.id,
    address: payment.address,
    amount: payment.crypto_amount,
    currency: payment.currency,
    qr: payment.qr_code_url,
    expires_at: payment.expires_at,
  });
}

클라이언트 컴포넌트

API를 호출하고 결제 세부 정보를 표시하는 React 컴포넌트를 생성합니다.

'use client';

import { useState } from 'react';

interface PaymentData {
  paymentId: string;
  address: string;
  amount: string;
  currency: string;
  qr: string;
  expires_at: string;
}

export default function PaymentButton({ amount }: { amount: number }) {
  const [payment, setPayment] = useState(null);
  const [loading, setLoading] = useState(false);

  async function handlePay(currency: string) {
    setLoading(true);
    const res = await fetch('/api/payments', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount, currency, metadata: { orderId: '123' } }),
    });
    const data = await res.json();
    setPayment(data);
    setLoading(false);
  }

  if (payment) {
    return (
      <>
        <h3>Send {payment.amount} {payment.currency}</h3>
        <p>{payment.address}</p>
        <button onClick={() => navigator.clipboard.writeText(payment.address)}>
          Copy Address
        </button>
      </>
    );
  }

  return (
    <>
      <button onClick={() => {/* trigger payment UI */}}>
        Pay ${amount}
      </button>
      {['BTC', 'ETH', 'SOL', 'USDC'].map((c) => (
        <button
          key={c}
          onClick={() => handlePay(c)}
          disabled={loading}
        >
          {c}
        </button>
      ))}
    </>
  );
}

웹훅 핸들러

app/api/webhooks/coinpay/route.ts 파일을 생성하여 결제 알림을 처리합니다.

import { NextRequest, NextResponse } from 'next/server';
import crypto from 'crypto';

const WEBHOOK_SECRET = process.env.COINPAY_WEBHOOK_SECRET!;

function verifySignature(payload: string, signature: string): boolean {
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

export async function POST(req: NextRequest) {
  const body = await req.text();
  const signature = req.headers.get('x-coinpay-signature') || '';

  if (!verifySignature(body, signature)) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  const event = JSON.parse(body);

  switch (event.status) {
    case 'confirmed':
      // Payment confirmed on‑chain
      // Update your order, grant access, send receipt
      console.log(`Payment ${event.payment_id} confirmed for ${event.amount} ${event.currency}`);
      break;
    case 'expired':
      // Payment window expired
      break;
  }

  return NextResponse.json({ received: true });
}

환경 변수

다음 변수를 .env 파일(또는 호스팅 플랫폼의 비밀 저장소)에 추가하세요:

COINPAY_API_KEY=your_api_key_here
COINPAY_WEBHOOK_SECRET=your_webhook_secret_here
NEXT_PUBLIC_BASE_URL=https://yourapp.com

결론

대략 5분과 4개의 파일만으로, 여러분의 Next.js 애플리케이션은 중개인 없이 직접 암호화폐 결제를 받을 수 있습니다. 각 결제는 여러분 자체 HD 지갑에서 파생된 주소로 전송되어 완전한 제어권을 제공합니다.

BitPay나 Coinbase Commerce와 같은 서비스와 차별화되는 점은?
여러분의 개인 키는 서버에 그대로 보관되므로, 어떠한 관리 기관도 자금을 동결하거나 보류할 수 없으며, 자금을 해제하기 위해 KYC 절차가 필요하지 않습니다.

추가 읽을거리:
📖 CoinPay documentation

패키지: @profullstack/coinpay

0 조회
Back to Blog

관련 글

더 보기 »

Angular 21에서 Signal Forms

Angular 21 Signal Forms – 새로운 사고 모델 수년간 Angular 폼은 하나의 의미만을 가지고 있었습니다: FormGroup, FormControl, valueChanges, 그리고 AbstractControl 트리.

📦Redux란 무엇인가?

프론트엔드 개발을 배우고 있다면, 특히 React와 함께라면 Redux에 대해 들어봤을 것입니다. 처음에는 혼란스러워 보일 수 있지만, 핵심 아이디어는 간단합니다....