搜索

PythonReactSEOPDF
GitHub Skill

paypal

Integrates PayPal payments with the JavaScript SDK for checkout buttons and card fields. Use when accepting PayPal, Venmo, Pay Later, and credit card payments in web applications.

mgd34msu☆ 3 仓库 Stars0 仓库 Forks

安装与使用

请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。

查看来源 ↗使用指南

技能说明

PayPal JavaScript SDK

Accept PayPal, Venmo, Pay Later, and credit/debit cards. Renders smart payment buttons that adapt to buyer preferences.

Quick Start

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&currency=USD"></script>

<div id="paypal-button-container"></div>

<script>
paypal.Buttons({
  createOrder: async () => {
    const response = await fetch('/api/orders', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        amount: '99.00'
      })
    });
    const data = await response.json();
    return data.id;
  },
  onApprove: async (data) => {
    const response = await fetch(`/api/orders/${data.orderID}/capture`, {
      method: 'POST'
    });
    const details = await response.json();
    alert(`Transaction completed by ${details.payer.name.given_name}`);
  }
}).render('#paypal-button-container');
</script>

SDK Configuration

Script Parameters
<!-- Basic -->
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID"></script>

<!-- With options -->
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&currency=USD&intent=capture&components=buttons,card-fields"></script>
Parameter Description Values
client-id Your PayPal client ID Required
currency Transaction currency USD, EUR, GBP, etc.
intent Payment intent capture (default), authorize
components SDK components to load buttons, card-fields, marks
disable-funding Disable payment methods credit, paylater, venmo, card
enable-funding Enable payment methods venmo, paylater
Dynamic Loading
// Load SDK dynamically
function loadPayPalScript(clientId) {
  return new Promise((resolve) => {
    const script = document.createElement('script');
    script.src = `https://www.paypal.com/sdk/js?client-id=${clientId}&currency=USD`;
    script.onload = () => resolve(window.paypal);
    document.body.appendChild(script);
  });
}

const paypal = await loadPayPalScript('YOUR_CLIENT_ID');

Payment Buttons

Basic Buttons
paypal.Buttons({
  createOrder: (data, actions) => {
    return actions.order.create({
      purchase_units: [{
        amount: {
          value: '99.00'
        }
      }]
    });
  },
  onApprove: (data, actions) => {
    return actions.order.capture().then((details) => {
      console.log('Transaction completed:', details);
    });
  }
}).render('#paypal-button-container');
Server-Side Integration (Recommended)
paypal.Buttons({
  // Create order on server
  createOrder: async () => {
    const response = await fetch('/api/paypal/orders', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        items: [
          { name: 'Product', quantity: 1, price: '99.00' }
        ]
      })
    });
    const order = await response.json();
    return order.id;
  },

  // Capture on server
  onApprove: async (data) => {
    const response = await fetch(`/api/paypal/orders/${data.orderID}/capture`, {
      method: 'POST'
    });
    const details = await response.json();

    if (details.status === 'COMPLETED') {
      // Show success message
      window.location.href = '/success';
    }
  },

  onCancel: (data) => {
    console.log('Order cancelled:', data.orderID);
    // Return to cart
  },

  onError: (err) => {
    console.error('PayPal error:', err);
    // Show error message
  }
}).render('#paypal-button-container');
Button Styling
paypal.Buttons({
  style: {
    layout: 'vertical',     // vertical, horizontal
    color: 'gold',          // gold, blue, silver, white, black
    shape: 'rect',          // rect, pill
    label: 'paypal',        // paypal, checkout, buynow, pay, subscribe
    height: 40,             // 25-55
    tagline: false          // Show "The safer, easier way to pay"
  },
  createOrder: () => { /* ... */ },
  onApprove: () => { /* ... */ }
}).render('#paypal-button-container');
Standalone Buttons
// PayPal only
paypal.Buttons({
  fundingSource: paypal.FUNDING.PAYPAL,
  createOrder: () => { /* ... */ },
  onApprove: () => { /* ... */ }
}).render('#paypal-button');

// Venmo only
paypal.Buttons({
  fundingSource: paypal.FUNDING.VENMO,
  createOrder: () => { /* ... */ },
  onApprove: () => { /* ... */ }
}).render('#venmo-button');

// Pay Later
paypal.Buttons({
  fundingSource: paypal.FUNDING.PAYLATER,
  createOrder: () => { /* ... */ },
  onApprove: () => { /* ... */ }
}).render('#paylater-button');

Card Fields

Accept credit/debit cards directly on your site.

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&components=card-fields"></script>

<div id="card-name-field-container"></div>
<div id="card-number-field-container"></div>
<div id="card-expiry-field-container"></div>
<div id="card-cvv-field-container"></div>
<button id="card-submit-button">Pay with Card</button>
const cardField = paypal.CardFields({
  createOrder: async () => {
    const response = await fetch('/api/paypal/orders', {
      method: 'POST',
      body: JSON.stringify({ amount: '99.00' })
    });
    const data = await response.json();
    return data.id;
  },
  onApprove: async (data) => {
    const response = await fetch(`/api/paypal/orders/${data.orderID}/capture`, {
      method: 'POST'
    });
    const details = await response.json();
    console.log('Card payment completed:', details);
  },
  onError: (err) => {
    console.error('Card error:', err);
  }
});

// Check if card fields are eligible
if (cardField.isEligible()) {
  // Render individual fields
  cardField.NameField().render('#card-name-field-container');
  cardField.NumberField().render('#card-number-field-container');
  cardField.ExpiryField().render('#card-expiry-field-container');
  cardField.CVVField().render('#card-cvv-field-container');

  // Submit handler
  document.getElementById('card-submit-button').addEventListener('click', () => {
    cardField.submit();
  });
}
Card Field Styling
const cardField = paypal.CardFields({
  style: {
    input: {
      'font-size': '16px',
      'font-family': 'monospace',
      color: '#333'
    },
    '.invalid': {
      color: '#dc3545'
    }
  },
  createOrder: () => { /* ... */ },
  onApprove: () => { /* ... */ }
});

Server-Side API (Node.js)

Setup
npm install @paypal/paypal-server-sdk
import { PayPalHttpClient, SandboxEnvironment, LiveEnvironment } from '@paypal/paypal-server-sdk';

const environment = process.env.NODE_ENV === 'production'
  ? new LiveEnvironment(
      process.env.PAYPAL_CLIENT_ID!,
      process.env.PAYPAL_CLIENT_SECRET!
    )
  : new SandboxEnvironment(
      process.env.PAYPAL_SANDBOX_CLIENT_ID!,
      process.env.PAYPAL_SANDBOX_CLIENT_SECRET!
    );

const client = new PayPalHttpClient(environment);
Create Order
// app/api/paypal/orders/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { amount, items } = await request.json();

  const accessToken = await getAccessToken();

  const response = await fetch('https://api-m.sandbox.paypal.com/v2/checkout/orders', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${accessToken}`
    },
    body: JSON.stringify({
      intent: 'CAPTURE',
      purchase_units: [{
        amount: {
          currency_code: 'USD',
          value: amount,
          breakdown: {
            item_total: { currency_code: 'USD', value: amount }
          }
        },
        items: items.map((item: any) => ({
          name: item.name,
          quantity: String(item.quantity),
          unit_amount: {
            currency_code: 'USD',
            value: item.price
          }
        }))
      }]
    })
  });

  const order = await response.json();
  return NextResponse.json(order);
}

async function getAccessToken() {
  const auth = Buffer.from(
    `${process.env.PAYPAL_CLIENT_ID}:${process.env.PAYPAL_CLIENT_SECRET}`
  ).toString('base64');

  const response = await fetch('https://api-m.sandbox.paypal.com/v1/oauth2/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      Authorization: `Basic ${auth}`
    },
    body: 'grant_type=client_credentials'
  });

  const data = await response.json();
  return data.access_token;
}
Capture Order
// app/api/paypal/orders/[orderId]/capture/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(
  request: NextRequest,
  { params }: { params: { orderId: string } }
) {
  const accessToken = await getAccessToken();

  const response = await fetch(
    `https://api-m.sandbox.paypal.com/v2/checkout/orders/${params.orderId}/capture`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`
      }
    }
  );

  const capture = await response.json();

  if (capture.status === 'COMPLETED') {
    // Update database, send confirmation email, etc.
    const transactionId = capture.purchase_units[0].payments.captures[0].id;
    console.log('Payment captured:', transactionId);
  }

  return NextResponse.json(capture);
}

Subscriptions

<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID&vault=true&intent=subscription"></script>
paypal.Buttons({
  style: {
    label: 'subscribe'
  },
  createSubscription: (data, actions) => {
    return actions.subscription.create({
      plan_id: 'P-XXXXXXXXXXXXXXXXXXXXXXXX'
    });
  },
  onApprove: (data) => {
    console.log('Subscription ID:', data.subscriptionID);
    // Save subscription ID to database
  }
}).render('#paypal-button-container');
Server-Side Subscription Management
// Create subscription plan
async function createPlan(accessToken: string) {
  const response = await fetch('https://api-m.sandbox.paypal.com/v1/billing/plans', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${accessToken}`
    },
    body: JSON.stringify({
      product_id: 'PROD-XXXXX',
      name: 'Monthly Plan',
      billing_cycles: [{
        frequency: { interval_unit: 'MONTH', interval_count: 1 },
        tenure_type: 'REGULAR',
        sequence: 1,
        total_cycles: 0,
        pricing_scheme: {
          fixed_price: { value: '9.99', currency_code: 'USD' }
        }
      }],
      payment_preferences: {
        auto_bill_outstanding: true,
        payment_failure_threshold: 3
      }
    })
  });

  return response.json();
}

// Cancel subscription
async function cancelSubscription(subscriptionId: string, accessToken: string) {
  await fetch(
    `https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}/cancel`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`
      },
      body: JSON.stringify({
        reason: 'Customer requested cancellation'
      })
    }
  );
}

Webhooks

Setup Webhook Handler
// app/api/webhooks/paypal/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const body = await request.json();
  const headers = Object.fromEntries(request.headers);

  // Verify webhook signature
  const isValid = await verifyWebhookSignature(headers, body);
  if (!isValid) {
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  const eventType = body.event_type;

  switch (eventType) {
    case 'CHECKOUT.ORDER.APPROVED':
      console.log('Order approved:', body.resource.id);
      break;

    case 'PAYMENT.CAPTURE.COMPLETED':
      console.log('Payment captured:', body.resource.id);
      // Fulfill order
      break;

    case 'PAYMENT.CAPTURE.DENIED':
      console.log('Payment denied:', body.resource.id);
      // Handle failed payment
      break;

    case 'BILLING.SUBSCRIPTION.CREATED':
      console.log('Subscription created:', body.resource.id);
      break;

    case 'BILLING.SUBSCRIPTION.ACTIVATED':
      console.log('Subscription activated:', body.resource.id);
      // Grant access
      break;

    case 'BILLING.SUBSCRIPTION.CANCELLED':
      console.log('Subscription cancelled:', body.resource.id);
      // Revoke access
      break;

    case 'PAYMENT.SALE.COMPLETED':
      console.log('Subscription payment:', body.resource.id);
      // Update billing records
      break;
  }

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

async function verifyWebhookSignature(headers: any, body: any) {
  const accessToken = await getAccessToken();

  const response = await fetch(
    'https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`
      },
      body: JSON.stringify({
        auth_algo: headers['paypal-auth-algo'],
        cert_url: headers['paypal-cert-url'],
        transmission_id: headers['paypal-transmission-id'],
        transmission_sig: headers['paypal-transmission-sig'],
        transmission_time: headers['paypal-transmission-time'],
        webhook_id: process.env.PAYPAL_WEBHOOK_ID,
        webhook_event: body
      })
    }
  );

  const result = await response.json();
  return result.verification_status === 'SUCCESS';
}

React Integration

// components/PayPalButton.tsx
'use client';

import { useEffect, useRef } from 'react';

interface PayPalButtonProps {
  amount: string;
  onSuccess: (details: any) => void;
}

export function PayPalButton({ amount, onSuccess }: PayPalButtonProps) {
  const buttonRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const script = document.createElement('script');
    script.src = `https://www.paypal.com/sdk/js?client-id=${process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID}&currency=USD`;
    script.async = true;

    script.onload = () => {
      if (buttonRef.current) {
        window.paypal.Buttons({
          createOrder: async () => {
            const response = await fetch('/api/paypal/orders', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ amount })
            });
            const order = await response.json();
            return order.id;
          },
          onApprove: async (data: any) => {
            const response = await fetch(
              `/api/paypal/orders/${data.orderID}/capture`,
              { method: 'POST' }
            );
            const details = await response.json();
            onSuccess(details);
          }
        }).render(buttonRef.current);
      }
    };

    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    };
  }, [amount, onSuccess]);

  return <div ref={buttonRef} />;
}
Using @paypal/react-paypal-js
npm install @paypal/react-paypal-js
import { PayPalScriptProvider, PayPalButtons } from '@paypal/react-paypal-js';

function App() {
  return (
    <PayPalScriptProvider options={{
      clientId: process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID!,
      currency: 'USD'
    }}>
      <PayPalButtons
        style={{ layout: 'vertical' }}
        createOrder={async () => {
          const response = await fetch('/api/paypal/orders', {
            method: 'POST',
            body: JSON.stringify({ amount: '99.00' })
          });
          const order = await response.json();
          return order.id;
        }}
        onApprove={async (data) => {
          const response = await fetch(
            `/api/paypal/orders/${data.orderID}/capture`,
            { method: 'POST' }
          );
          const details = await response.json();
          console.log('Success:', details);
        }}
      />
    </PayPalScriptProvider>
  );
}

Environment Variables

# Production
PAYPAL_CLIENT_ID=your_client_id
PAYPAL_CLIENT_SECRET=your_client_secret
PAYPAL_WEBHOOK_ID=your_webhook_id

# Sandbox (testing)
PAYPAL_SANDBOX_CLIENT_ID=your_sandbox_client_id
PAYPAL_SANDBOX_CLIENT_SECRET=your_sandbox_client_secret

# Client-side
NEXT_PUBLIC_PAYPAL_CLIENT_ID=your_client_id

API Endpoints

Environment Base URL
Sandbox https://api-m.sandbox.paypal.com
Production https://api-m.paypal.com

Best Practices

  1. Server-side capture - Always capture payments server-side
  2. Verify webhooks - Validate signatures before processing
  3. Test in sandbox - Use sandbox environment for development
  4. Handle errors - Implement onError and onCancel handlers
  5. Store transaction IDs - Save for refunds and disputes
  6. Idempotent handlers - Webhooks may be delivered multiple times
  7. Show loading states - Disable buttons during processing

使用示例

查看来源仓库中的使用示例与配置说明。

查看来源 ↗

来源历史

收录时间
2026-01-20
索引更新时间
2026-01-28
Branch
main

收录与同步日期属于本站记录。源码修改历史请查看来源仓库。

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!