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.
Integrates PayPal payments using the JavaScript SDK for checkout buttons and card fields. Use when building payment forms that accept PayPal, Venmo, Pay Later, and credit cards in web applications.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Accept PayPal, Venmo, Pay Later, and credit/debit cards. Renders smart payment buttons that adapt to buyer preferences.
<script src="https://www.paypal.com/sdk/js?client-id=YOUR_CLIENT_ID¤cy=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>
<!-- 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¤cy=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 |
// 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}¤cy=USD`;
script.onload = () => resolve(window.paypal);
document.body.appendChild(script);
});
}
const paypal = await loadPayPalScript('YOUR_CLIENT_ID');
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');
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');
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');
// 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');
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();
});
}
const cardField = paypal.CardFields({
style: {
input: {
'font-size': '16px',
'font-family': 'monospace',
color: '#333'
},
'.invalid': {
color: '#dc3545'
}
},
createOrder: () => { /* ... */ },
onApprove: () => { /* ... */ }
});
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);
// 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;
}
// 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);
}
<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');
// 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'
})
}
);
}
// 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';
}
// 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}¤cy=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} />;
}
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>
);
}
# 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
| Environment | Base URL |
|---|---|
| Sandbox | https://api-m.sandbox.paypal.com |
| Production | https://api-m.paypal.com |
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.