360 Secure SkillHub
360 安全技能中心

payram-checkout-integration

该 Skill 说明如何用 PayRam API 实现加密支付结账:创建支付、跳转支付页、查询支付状态并处理错误,提供 Node.js SDK 及 Python、Go、PHP、Java 的 HTTP 示例,并列出 Express、Next.js 等框架路由写法、轮询模式与数据库表结构,还引用 PayRam MCP 代码生成工具。

PayRam
热度 0.00
最近更新 2026-10-18 21:11:37
分类:开发依赖:第三方 API / MCP 服务应用场景:API 集成 / 代码生成 / 财务

安装技能

复制下面的话术发给你的 Agent,它会通过 secure-skills 检索并安装该技能。

执行命令安装此 skill: npx secure-skills-cli add payram/payram-mcp/payram-checkout-integration
Metadata
name
payram-checkout-integration
description
Integrate PayRam checkout flow into web applications. Generate payment links, embed payment pages, handle redirects, and process payment confirmations. Supports Express, Next.js, FastAPI, Laravel, Gin, Spring Boot. Use when adding crypto checkout to e-commerce, building payment forms, implementing deposit flows, or creating hosted payment pages for crypto acceptance.

PayRam Checkout Integration

First time with PayRam? See payram-setup to configure your server, API keys, and wallets.

Implement payment acceptance flows using PayRam's API. Create payments, redirect users, and confirm transactions.

Payment Flow Overview

1. Your Backend → POST /api/v1/payment → PayRam
2. PayRam returns { url, reference_id, host }
3. Redirect user to payment URL
4. User selects chain/token, sends payment
5. PayRam confirms on-chain → webhook to your backend
6. Your backend fulfills order

Payment States

Payments transition through these states:

  • OPEN — Payment created, awaiting customer action
  • FILLED — Customer sent exact amount, payment confirmed
  • PARTIALLY_FILLED — Partial payment received (less than requested)
  • OVER_FILLED — Overpayment received (more than requested)
  • CANCELLED — Payment manually cancelled
  • UNDEFINED — Unknown status (fallback)

SDK Integration (Node.js/TypeScript)

Install SDK

npm install payram dotenv

Create Payment with SDK

import { Payram, InitiatePaymentRequest, InitiatePaymentResponse, isPayramSDKError } from 'payram';

const payram = new Payram({
  apiKey: process.env.PAYRAM_API_KEY!,
  baseUrl: process.env.PAYRAM_BASE_URL!,
  config: {
    timeoutMs: 10_000,
    maxRetries: 2,
    retryPolicy: 'safe',
    allowInsecureHttp: false,
  },
});

export async function createCheckout(
  payload: InitiatePaymentRequest,
): Promise<InitiatePaymentResponse> {
  try {
    const checkout = await payram.payments.initiatePayment(payload);
    console.log('Redirect customer to:', checkout.url);
    console.log('Payment reference:', checkout.reference_id);
    return checkout;
  } catch (error) {
    if (isPayramSDKError(error)) {
      console.error('Payram Error:', {
        status: error.status,
        requestId: error.requestId,
        retryable: error.isRetryable,
      });
    }
    throw error;
  }
}

// Example usage
await createCheckout({
  customerEmail: 'customer@example.com',
  customerId: 'cust_123',
  amountInUSD: 49.99,
});

Required Fields:

  • customerEmail: Customer's email address
  • customerId: Your internal customer identifier
  • amountInUSD: Payment amount in USD

Optional Fields:

  • settlementCurrency: Currency for settlement (default: USD)
  • memo: Internal reference or description
  • redirectUrl: Custom URL to redirect after payment

Check Payment Status with SDK

import { Payram, PaymentRequestData, isPayramSDKError } from 'payram';

const payram = new Payram({
  apiKey: process.env.PAYRAM_API_KEY!,
  baseUrl: process.env.PAYRAM_BASE_URL!,
});

export async function getPaymentStatus(referenceId: string): Promise<PaymentRequestData> {
  try {
    const payment = await payram.payments.getPaymentRequest(referenceId);
    // paymentState ∈ OPEN | PARTIALLY_FILLED | FILLED | OVER_FILLED | CANCELLED.
    // filledAmount = crypto amount received; filledAmountInUSD = its USD value
    // (requires core >= 2026-07-25; older builds returned USD in filledAmount).
    console.log('Latest payment state:', payment.paymentState);
    console.log('Filled (crypto):', payment.filledAmount, '| USD:', payment.filledAmountInUSD);
    return payment;
  } catch (error) {
    if (isPayramSDKError(error)) {
      console.error('Payram Error:', {
        status: error.status,
        errorCode: error.error,
        requestId: error.requestId,
      });
    }
    throw error;
  }
}

HTTP Integration (Python, Go, PHP, Java)

API Endpoint

POST https://your-payram-server/api/v1/payment
Header: API-Key: your-api-key
Content-Type: application/json

Critical: PayRam uses API-Key header, NOT Authorization: Bearer.

Request Body:

{
  "customerEmail": "customer@example.com",
  "customerId": "user_12345",
  "amountInUSD": 25
}

Response:

{
  "host": "https://your-payram-server",
  "reference_id": "c80f5363-0397-4761-aa1a-3155c3a21470",
  "url": "https://your-payram-server/payments?reference_id=..."
}

Python (FastAPI)

import httpx
import os
from fastapi import APIRouter
from fastapi.responses import RedirectResponse

PAYRAM_BASE_URL = os.environ['PAYRAM_BASE_URL']
PAYRAM_API_KEY = os.environ['PAYRAM_API_KEY']

@router.post("/create-payment")
async def create_payment(email: str, user_id: str, amount: float):
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            f"{PAYRAM_BASE_URL}/api/v1/payment",
            json={"customerEmail": email, "customerId": user_id, "amountInUSD": amount},
            headers={"API-Key": PAYRAM_API_KEY}
        )
    return RedirectResponse(resp.json()["url"])

Go (Gin)

func CreatePayment(email, customerID string, amount float64) (*InitiatePaymentResponse, error) {
    body, _ := json.Marshal(map[string]interface{}{
        "customerEmail": email,
        "customerId":    customerID,
        "amountInUSD":   amount,
    })

    url := fmt.Sprintf("%s/api/v1/payment", os.Getenv("PAYRAM_BASE_URL"))
    req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("API-Key", os.Getenv("PAYRAM_API_KEY"))

    resp, err := http.DefaultClient.Do(req)
    // ... handle response
}

PHP (Laravel)

$ch = curl_init(getenv('PAYRAM_BASE_URL') . '/api/v1/payment');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'API-Key: ' . getenv('PAYRAM_API_KEY'),
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_RETURNTRANSFER => true,
]);

Java (Spring Boot)

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(baseUrl + "/api/v1/payment"))
    .header("Content-Type", "application/json")
    .header("API-Key", apiKey)
    .POST(HttpRequest.BodyPublishers.ofString(payload))
    .build();

Framework Route Examples

Express.js Route

import { Router } from 'express';
import { Payram, InitiatePaymentRequest, isPayramSDKError } from 'payram';

const router = Router();
const payram = new Payram({
  apiKey: process.env.PAYRAM_API_KEY!,
  baseUrl: process.env.PAYRAM_BASE_URL!,
});

router.post('/api/payments/payram', async (req, res) => {
  const payload = req.body as Partial<InitiatePaymentRequest>;

  if (!payload?.customerEmail || !payload.customerId || typeof payload.amountInUSD !== 'number') {
    return res.status(400).json({ error: 'MISSING_REQUIRED_FIELDS' });
  }

  try {
    const checkout = await payram.payments.initiatePayment({
      customerEmail: payload.customerEmail,
      customerId: payload.customerId,
      amountInUSD: payload.amountInUSD,
    });
    return res.status(201).json({
      referenceId: checkout.reference_id,
      checkoutUrl: checkout.url,
    });
  } catch (error) {
    if (isPayramSDKError(error)) {
      console.error('Payram Error:', { status: error.status, requestId: error.requestId });
    }
    return res.status(502).json({ error: 'PAYRAM_CREATE_PAYMENT_FAILED' });
  }
});

Next.js App Router

import { NextRequest, NextResponse } from 'next/server';
import { Payram, InitiatePaymentRequest, isPayramSDKError } from 'payram';

const payram = new Payram({
  apiKey: process.env.PAYRAM_API_KEY!,
  baseUrl: process.env.PAYRAM_BASE_URL!,
});

export async function POST(request: NextRequest) {
  const payload = (await request.json()) as Partial<InitiatePaymentRequest>;

  if (!payload?.customerEmail || !payload.customerId || typeof payload.amountInUSD !== 'number') {
    return NextResponse.json({ error: 'MISSING_REQUIRED_FIELDS' }, { status: 400 });
  }

  try {
    const checkout = await payram.payments.initiatePayment({
      customerEmail: payload.customerEmail,
      customerId: payload.customerId,
      amountInUSD: payload.amountInUSD,
    });
    return NextResponse.json({
      referenceId: checkout.reference_id,
      checkoutUrl: checkout.url,
    });
  } catch (error) {
    if (isPayramSDKError(error)) {
      console.error('Payram Error:', { status: error.status, requestId: error.requestId });
    }
    return NextResponse.json({ error: 'PAYRAM_CREATE_PAYMENT_FAILED' }, { status: 502 });
  }
}

Status Polling Pattern

async function pollPaymentStatus(referenceId: string, maxAttempts = 10) {
  for (let i = 0; i < maxAttempts; i++) {
    const payment = await getPaymentStatus(referenceId);

    if (payment.paymentState === 'FILLED' || payment.paymentState === 'OVER_FILLED') {
      return payment;
    }

    if (payment.paymentState === 'CANCELLED') {
      throw new Error(`Payment ${payment.paymentState.toLowerCase()}`);
    }

    if (payment.paymentState === 'UNDEFINED') {
      throw new Error('Payment status undefined');
    }

    await new Promise((resolve) => setTimeout(resolve, Math.min(1000 * Math.pow(2, i), 30000)));
  }

  throw new Error('Payment status check timeout');
}

Database Schema

CREATE TABLE payments (
    id SERIAL PRIMARY KEY,
    customer_id VARCHAR(255) NOT NULL,
    payram_reference_id VARCHAR(255) UNIQUE NOT NULL,
    amount_usd DECIMAL(10, 2) NOT NULL,
    status VARCHAR(50) DEFAULT 'OPEN',
    checkout_url TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_payram_reference ON payments(payram_reference_id);
CREATE INDEX idx_customer_id ON payments(customer_id);

MCP Server Code Generation

Use the PayRam MCP server to generate framework-specific code:

Framework MCP Tool
JavaScript SDK generate_payment_sdk_snippet
Raw HTTP (any language) generate_payment_http_snippet
Express.js snippet_express_payment_route
Next.js App Router snippet_nextjs_payment_route
FastAPI snippet_fastapi_payment_route
Gin (Go) snippet_gin_payment_route
Laravel snippet_laravel_payment_route
Spring Boot snippet_spring_payment_route

Environment Configuration

# .env
PAYRAM_BASE_URL=https://your-payram-server
PAYRAM_API_KEY=your-api-key-here

Use generate_env_template MCP tool to scaffold this.

Error Handling

HTTP Code Meaning Action
200/201 Payment created Redirect to URL
401 Invalid API key Check API-Key header (NOT Authorization)
400 Invalid request Check required fields, amount > 0
404 Merchant not found Verify PAYRAM_BASE_URL
500 Server error Retry with backoff

All PayRam Skills

Skill What it covers
payram-setup Server config, API keys, wallet setup, connectivity test
payram-agent-onboarding Headless install and the agent CLI for AI agents
payram-analytics Analytics dashboards, reports, and payment insights via MCP tools
payram-crypto-payments Architecture overview, why PayRam, MCP tools
payram-payment-integration Quick-start payment integration guide
payram-self-hosted-payment-gateway Deploy and own your payment infrastructure
payram-checkout-integration Checkout flow with SDK + HTTP for 6 frameworks
payram-webhook-integration Webhook handlers for Express, Next.js, FastAPI, Gin, Laravel, Spring Boot
payram-stablecoin-payments USDT/USDC acceptance across EVM chains and Tron
payram-bitcoin-payments BTC with HD wallet derivation and mobile signing
payram-payouts Send crypto payouts and manage referral programs
payram-no-kyc-crypto-payments No-KYC, no-signup, permissionless payment acceptance

Support

Need help? Message the PayRam team on Telegram: @PayRamChat