关于 stripe-dispute
stripe-dispute 是面向使用 Stripe 的 SaaS 团队的争议评估与举证技能。它先依据成本和历史结果判断是否值得抗辩,再在获批后整理并提交证据。
主要功能
- 01评估抗辩成本与预期价值
- 02查询争议及付款记录
- 03只读查询用户活动数据
- 04生成活动日志与条款 PDF
- 05获批后向 Stripe 提交证据
适用场景
- 01评估 Stripe 拒付是否值得抗辩
- 02为争议整理用户登录和使用记录
- 03生成并提交账单及政策材料
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openclaudia/ openclaudia-skills --skill stripe-dispute安装后在 Claude Code 中输入/stripe-dispute确认已加载。
详细介绍
Stripe 争议评估与证据
先评估经济效益。只有在有理由提出争议且获得批准时,才整理证据包并提交给 Stripe。适用于任何使用 Stripe,并有包含登录或使用日志的用户数据库的 SaaS。
何时使用此技能
在以下情况下使用此技能:
- 收到 Stripe 拒付通知并希望对其提出抗辩
- 提供争议 ID(
du_*)并要求“反驳”/“申辩”/“抗辩” - 询问如何为标记为
fraudulent、product_not_received、product_unacceptable或subscription_canceled的争议收集证据 - 希望生成一份活动日志 PDF,以证明客户使用过其产品
所需环境变量
STRIPE_SECRET_KEY=sk_live_... # Stripe restricted/secret key with disputes:write scope
DATABASE_URL=postgres://... # READ-ONLY connection to your app's user database (optional but recommended)
TERMS_URL=https://yoursite.com/terms # URL to your published cancellation/refund policy
EVIDENCE_DIR=~/disputes # Where to save the per-customer evidence folders
**数据库安全:**所有查询都只能使用 SELECT。绝不允许此技能执行 UPDATE/DELETE/INSERT。
输入
用户提供以下任一信息:
- Stripe 争议 ID(
du_xxxxx)——首选 - 客户邮箱——此技能将查找争议
- 付款 ID(
ch_xxxxx或py_xxxxx)
先决定是否提出争议
接受争议也可能是正确的选择。绝不要仅仅因为存在争议案件就提交证据。
- 核实 Stripe 当前的价格。按目前美国标准定价,Stripe 会自动收取 15 美元的争议受理费,并在提交证据时再收取 15 美元的争议抗辩费。受理费无法退回。只有胜诉时才会退还抗辩费。如果这些金额有变动,请使用当前实时价格。
- 查询商户的 Stripe 实时争议历史。计算抗辩胜率时,只统计
evidence_details.submission_count > 0的已结案争议。区分首次购买和续订;样本允许时,再细分到相同理由。报告胜诉数、败诉数、未结案件数和样本量。若没有完全匹配的先例,请明确说明。 - 计算盈亏平衡胜率,以及扣除抗辩费和整理证据所需人力成本后的预期价值。不要仅凭案件强度臆测胜率。
- 除非用户提供了不同阈值,否则采用保守的 30% 最低胜率阈值。如果可比数据无法支持达到该阈值,建议不回应争议。这样可以避免抗辩费,但争议金额和受理费仍无法挽回。
- 在整理文件、上传证据或提交之前,必须获得用户的明确批准。提交操作不可撤销且会产生费用。
步骤
1. 从 Stripe 获取争议
curl -s -u "$STRIPE_SECRET_KEY:" \
"https://api.stripe.com/v1/disputes/$DISPUTE_ID" | python3 -m json.tool
提取:amount、reason、charge、evidence_details.due_by、evidence_details.submission_count、status。
如果 submission_count > 0,该争议已被抗辩——停止并提醒用户。
2. 获取相关背景信息
# Charge → tells you the payment method, risk score, billing details, customer ID
curl -s -u "$STRIPE_SECRET_KEY:" "https://api.stripe.com/v1/charges/$CHARGE_ID"
# Customer → name, email, default payment source
curl -s -u "$STRIPE_SECRET_KEY:" "https://api.stripe.com/v1/customers/$CUSTOMER_ID"
# All invoices for the customer → look for previously-undisputed payments
curl -s -u "$STRIPE_SECRET_KEY:" \
"https://api.stripe.com/v1/invoices?customer=$CUSTOMER_ID&limit=100"
# Subscription (if recurring)
curl -s -u "$STRIPE_SECRET_KEY:" "https://api.stripe.com/v1/subscriptions/$SUB_ID"
同一张银行卡此前未遭争议的付款可作为 fraudulent 索赔的佐证。务必统计这些付款,但不要单凭它们作为证明。
3. 在应用数据库中查找客户
根据你的架构调整这些查询。以下是一种实用的证据结构:
-- User profile and self-reported cancel reason
SELECT id, email, created_at, plan_tier, stripe_customer_id,
cancel_reason, cancelled_at, delete_reason
FROM users WHERE email ILIKE :email;
-- Login activity (timestamps + country + device)
SELECT created_at, country_code, device
FROM user_activity WHERE user_id = :uid ORDER BY created_at;
-- Things the customer created/used in your product
SELECT name, type, created_at, updated_at
FROM projects WHERE user_id = :uid AND deleted = false ORDER BY created_at;
-- Checkout / payment-related actions (proves intent)
SELECT timestamp, endpoint, payload FROM action_logs
WHERE user_id = :uid
AND endpoint ~* '(subscribe|checkout|stripe|upgrade|pay)'
ORDER BY timestamp DESC;
对于 product_not_received 索赔,请检查用户自行填写的 cancel_reason。如果用户取消时填写了“使用体验不佳”或任何承认使用过产品的内容,该字段就直接与索赔相矛盾。逐字引用该内容,但不要根据单一事实推断胜率。
4. 下载佐证文件
FOLDER="$EVIDENCE_DIR/$(echo $CUSTOMER_NAME | tr '[:upper:] ' '[:lower:]-')-$(date +%Y-%m)"
mkdir -p "$FOLDER"
# Invoice PDFs (URLs come from the Stripe invoice objects)
curl -sL "$INVOICE_PDF_URL" -o "$FOLDER/invoice.pdf"
5. 将服务条款/取消政策保存为 PDF
使用 Playwright(Node):
node -e "
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
await page.goto(process.env.TERMS_URL, { waitUntil: 'networkidle' });
await page.pdf({ path: process.argv[1], format: 'A4', printBackground: true });
await browser.close();
})();
" "$FOLDER/cancellation_policy.pdf"
6. 生成活动日志 PDF
生成一份简洁、便于审核的 HTML 活动日志,然后使用 WeasyPrint 将其转换为 PDF:
from weasyprint import HTML
HTML('activity_log.html').write_pdf('activity_log.pdf')
HTML 必须包含 <meta charset="UTF-8">,以免客户姓名和地址中的字符乱码。
便于审核的布局:
- 摘要网格 — 客户 / 电子邮件 / 内部用户 ID / Stripe 客户 ID / 账户创建时间 / 套餐 / 订阅开始时间 / 取消时间戳(附上与注册时间的间隔)/ 自述取消原因 / 已使用的点数或单位 / 购买 IP / 账单地址 / 付款方式(后四位、品牌)/ Stripe 风险评估 / 推荐来源 / 付款触发方式
- 付款历史表 — 列出每张发票的日期、金额和状态。用红色突出显示争议行。添加“是否有争议?”列,并明确填写“是”或“否”。
- 结账尝试表 — 证明客户有意购买(可反驳
fraudulent争议理由) - 已创建 / 已使用项目表 — 名称、类型、时间戳。具体用量比形容词更有说服力。
- 登录活动日志 — 每次会话均列出时间戳、国家/地区和设备。一致性 = 同一持卡人。
- 时间线摘要 — 按时间顺序撰写一段叙述,结尾为“随后于 $DATE 提交了争议。”
- 结论段落 — 如果用户自己的
cancel_reason与所述争议理由矛盾,则引用该原因。
优先使用具体数字,而非形容词。“29 次登录会话、3 个已命名项目、已使用 29,960 点数”比“使用频繁”更有用。
7. 提交前向用户展示所有内容
open "$FOLDER"
展示反驳文本、证据文件和胜诉概率评估。等待用户明确批准。
8. 将证据文件上传到 Stripe
文件应上传至 files.stripe.com,而不是 api.stripe.com——这是不同的主机:
curl -s -u "$STRIPE_SECRET_KEY:" \
-F "purpose=dispute_evidence" \
-F "file=@$FOLDER/activity_log.pdf" \
https://files.stripe.com/v1/files
返回 {"id": "file_xxx", ...}。记录 id——你需要在证据字段中引用它。
每项争议都必须使用单独的 file_id。 如果你试图在多个争议中重复使用同一个 file_id,Stripe 会拒绝请求并返回 400 "That file is already attached to something else"(尤其是对于 service_documentation)。当针对同一客户处理 N 项争议时,请为每份共用 PDF 上传 N 个副本——内容相同,但每次都使用新的 file_id。
9. 提交证据(仅一次——submit=true 不可撤销)
curl -s -u "$STRIPE_SECRET_KEY:" \
-X POST "https://api.stripe.com/v1/disputes/$DISPUTE_ID" \
-d "evidence[uncategorized_text]=$REBUTTAL_TEXT" \
-d "evidence[uncategorized_file]=$ACTIVITY_LOG_FILE_ID" \
-d "evidence[receipt]=$INVOICE_FILE_ID" \
-d "evidence[cancellation_policy]=$TERMS_FILE_ID" \
-d "evidence[cancellation_policy_disclosure]=$CANCEL_DISCLOSURE_TEXT" \
-d "evidence[refund_policy]=$TERMS_FILE_ID" \
-d "evidence[refund_policy_disclosure]=$REFUND_DISCLOSURE_TEXT" \
-d "evidence[cancellation_rebuttal]=$CANCEL_REBUTTAL_TEXT" \
-d "evidence[access_activity_log]=$ACCESS_LOG_SUMMARY" \
-d "evidence[service_date]=$SERVICE_START_DATE" \
-d "evidence[product_description]=$PRODUCT_DESCRIPTION" \
-d "evidence[customer_email_address]=$CUSTOMER_EMAIL" \
-d "evidence[customer_name]=$CUSTOMER_NAME" \
-d "evidence[customer_purchase_ip]=$PURCHASE_IP" \
-d "evidence[billing_address]=$BILLING_ADDRESS" \
-d "submit=true" \
"https://api.stripe.com/v1/disputes/$DISPUTE_ID"
验证响应:
status应为under_reviewevidence_details.has_evidence应为trueevidence_details.submission_count应为1
按争议理由制定证据策略
fraudulent
目标:证明持卡人进行了购买。
- 使用同一张卡进行过此前无争议的付款(最有力)
- OAuth 登录(Google/Apple)= 已验证身份的注册
- 不同会话间的 IP、国家/地区和设备保持一致
- 购买前多次尝试结账 = 有真实用户在考虑购买
- Stripe 自身的风险评估为
normal - 订阅仍处于有效状态且未取消
product_not_received
目标:证明已交付并被使用。
- 登录活动日志
- 在产品中创建的项目 / 执行的操作
- 客户本人自述的取消原因,如果已取消——逐字引用,以反驳争议理由
- 收据和欢迎邮件
product_unacceptable
目标:证明产品符合其描述,且客户使用过该产品。
- 与
product_not_received相同,另加服务条款中关于质量 / 退款政策的内容 - 突出说明客户从未提交支持工单
subscription_canceled
目标:证明客户从未取消订阅(或是在续订后才取消)。
- 订阅对象显示续订日期的
cancel_at_period_end=false - 续订日期之后的所有登录 / 使用活动
- 服务条款中说明年度续订需要明确取消
反驳模板
uncategorized_text
[Customer name] 于 [date] 通过 [auth method] 创建了 [Product name] 账户,并使用同一张 [card brand] 卡订阅了 [plan]($[amount]/[interval])。前 [N] 笔付款均未遭到争议。该客户积极使用了这项服务:[device] 上来自 [country] 的 [N] 次登录会话,创建了 [N] 个项目([list]),并消耗了 [N] [units]。遭到争议的款项是 [date] 的[续订/初始]付款。订阅当时为 [status],目前仍为[有效/已取消]。该客户从未联系支持团队取消订阅或申请退款。我们的取消和退款政策发布于 [TERMS_URL]。这并非欺诈交易——这是持卡人发起的合法购买,该持卡人已在此账户上进行了其他 [N] 笔未遭争议的付款。
cancellation_policy_disclosure
我们的取消政策发布于 [TERMS_URL]。订阅者可随时取消,并在当前计费周期结束前继续使用服务。该客户从未取消订阅。
refund_policy_disclosure
我们的退款政策发布于 [TERMS_URL]。我们提供 [N] 天退款保证。该客户未在此期限内申请退款,也从未在任何时候申请退款。
重要说明
- 文件上传至
files.stripe.com,而非api.stripe.com - 每笔争议只能提交一次。
submit=true后即为最终提交 - 证据提交截止时间为
evidence_details.due_by(Unix 时间戳)。超过截止时间后将无法再提交 - 数据库查询必须为只读——如可行,请限制连接角色的权限
- 活动日志 PDF 中不得包含其他客户的数据
- 将每个证据包保存到磁盘,以便在该客户未来发生争议时查阅
高价值矛盾模式
客户注册后短暂使用产品,几小时内在应用内取消表单中以“用户体验不佳”为由取消,几天后却提出拒付,声称“未收到产品”。
取消表单中的原因与拒付声明直接矛盾。在驳回说明中逐字引用该内容,同时仍须遵循费用和历史结果决策门控。
当争议原因为 product_not_received 或 product_unacceptable 时,务必首先检查 users.cancel_reason(或等效字段)。