用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/skeletorflet/opencode-kit --skill payment-integration命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Web accessibility (a11y). WCAG 2.1, ARIA, keyboard navigation, screen readers, testing tools.
Analytics and event tracking. Product analytics, Mixpanel, PostHog, Segment, GDPR compliance, event taxonomy.
UI animation patterns. CSS transitions, Framer Motion, GSAP, performance, accessibility.
基于 SOC 职业分类
正在显示 SKILL.md
| name | payment-integration |
| description | Payment integration patterns. Stripe, webhooks, subscriptions, one-time payments, PCI compliance. |
Payments are critical path. Test every failure scenario.
Client Server Stripe
│ │ │
├─ Create PaymentIntent ─→ │
│ ├── POST /payment_intents → │
│ │←── { client_secret } ──── │
│←── { client_secret } ┤ │
│ │ │
├─ Confirm (Stripe.js) ─────────────────────→
│←────────── redirect / success ────────────┤
│ │ │
│ ← webhook ─────────────── │
│ (payment_intent.succeeded)
// Server: create session
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: [{
price_data: {
currency: "usd",
product_data: { name: "Pro Plan" },
unit_amount: 2900, // $29.00 in cents
},
quantity: 1,
}],
mode: "payment",
success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${baseUrl}/cancel`,
metadata: { userId: user.id },
});
return { url: session.url };
// Create subscription
const subscription = await stripe.subscriptions.create({
customer: customer.stripeCustomerId,
items: [{ price: priceId }],
payment_behavior: "default_incomplete",
payment_settings: { save_default_payment_method: "on_subscription" },
expand: ["latest_invoice.payment_intent"],
});
// DB: store subscription.id, status, current_period_end
// ALWAYS verify webhook signature
app.post("/webhooks/stripe",
express.raw({ type: "application/json" }),
async (req, res) => {
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
req.body,
req.headers["stripe-signature"]!,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch {
return res.status(400).send("Webhook signature invalid");
}
// Idempotency: check if processed
const exists = await db.webhookEvents.findUnique({ where: { id: event.id } });
if (exists) return res.json({ received: true });
await db.webhookEvents.create({ data: { id: event.id, type: event.type } });
switch (event.type) {
case "payment_intent.succeeded":
(event.. .);
;
:
(event.. .);
;
:
(event.. .);
;
:
(event.. .);
;
}
res.({ : });
}
);
// Let customers manage billing themselves
const portalSession = await stripe.billingPortal.sessions.create({
customer: user.stripeCustomerId,
return_url: `${baseUrl}/dashboard`,
});
redirect(portalSession.url);
| Event | Action |
|---|---|
payment_intent.succeeded | Fulfill order |
invoice.paid | Extend subscription |
invoice.payment_failed | Email user, retry |
customer.subscription.updated | Sync plan in DB |
customer.subscription.deleted | Downgrade access |
checkout.session.completed | Provision product |
model User {
stripeCustomerId String? @unique
subscriptionId String? @unique
subscriptionStatus String? // active, trialing, past_due, canceled
currentPeriodEnd DateTime?
plan String @default("free")
}
model WebhookEvent {
id String @id // Stripe event ID
type String
processedAt DateTime @default(now())
}
PCI DSS SAQ A (lowest scope) requires:
├── NEVER touch raw card data on your server
├── Use Stripe.js / Elements (tokenize client-side)
├── HTTPS everywhere
├── Store only: last4, brand, exp — NO full card numbers
└── Stripe handles the rest (they are PCI Level 1)
// Stripe test cards
4242 4242 4242 4242 // Success
4000 0025 0000 3155 // 3D Secure required
4000 0000 0000 9995 // Always declined
4000 0000 0000 0341 // Attach fails
// Test webhooks locally
stripe listen --forward-to localhost:3000/webhooks/stripe
"""