App 审核质量要求
对于提交到应用市场的每一个 App,Stripe 都会按照一整套质量要求进行审核。在开发前就吃透这些标准,可以节省时间,减少来回修改的次数。
概览
Stripe App 审核会从六个关键维度评估你的 App:
- 透明定价,清晰传达费用
- App 功能,可靠且完整
- 开发规范,代码质量与 API 使用方式
- UX 质量,界面与体验标准
- 安全,数据保护与安全实践
- 法律合规,隐私与监管要求
透明定价
你的 App 必须向用户清楚说明所有费用:
- 定价披露:所有价格都必须在应用市场的展示页面中提前写明
- 无隐藏费用:用户在安装后不应遇到意料之外的收费
- 试用条款:如果提供试用,要写清时长以及试用结束后会发生什么
- 升级流程:任何加购或升级提示都必须不打扰用户,并明确标注为可选
- 货币:尽可能以用户所在地的货币展示价格
Caution
隐瞒定价,或在没有明确同意的情况下向用户收费的 App,会被直接拒绝。
日期与时间格式
App 中显示的所有日期和时间都必须遵循 Stripe Dashboard 的惯例:
- 有条件时按用户所在区域设置格式化日期
- 按用户所在时区显示时间
- 近期事件使用相对时间戳(例如 “2 hours ago”)
- 较早的事件使用带完整日期和时间的绝对时间戳
- 面向 API 的日期字段一律遵循 ISO 8601
// Good: Use Stripe's date formatting utilitiesimport { formatDate, formatRelativeTime } from '@stripe/ui-extension-sdk/utils';
const formattedDate = formatDate(timestamp); // Locale-awareconst relativeTime = formatRelativeTime(timestamp); // "2 hours ago"App 设置
如果你的 App 需要配置:
- 提供一个可从 App 视口进入的专用 设置视图
- 尽可能预填合理的默认值
- 校验所有用户输入,并给出清晰的错误提示
- 让用户无需重装 App 就能更新设置
- 使用 Stripe Secret Store API 跨会话保存设置
沙箱支持
你的 App 必须能在 Stripe 沙箱(测试)模式下正常工作:
- 测试模式兼容:所有功能都必须能在测试模式下运行
- 测试数据:使用贴近真实的测试数据来演示 App 功能
- 沙箱中不出现真实数据:绝不能在测试模式下暴露生产数据
- 优雅降级:如果某功能在沙箱中不可用,要显示清晰的说明解释原因
- 在清单文件中设置
sandbox_install_compatible: true
{ "sandbox_install_compatible": true}App 功能
可靠性
- App 在正常使用过程中不得崩溃或卡死
- 所有宣传过的功能都必须与描述一致
- 网络错误必须被妥善处理,并提供重试选项
- 后台操作进行时,App 必须保持响应
完整性
- 不得有占位内容、“即将推出” 的功能或失效链接
- 所有 UI 元素都必须可用,不能有失效按钮或无响应控件
- 帮助文本和文档链接必须指向有效页面
- 卸载时必须彻底清除所有 App 数据和 Webhook
性能
- 在常规网络下,UI 必须在 3 秒内渲染完成
- 后台同步操作不得阻塞 UI
- 大数据集必须使用分页或懒加载
- 尽量减少 API 调用,避免触发限流
开发规范
API 使用
- 使用最新的稳定版 Stripe API
- 在分页、错误处理和幂等性上遵循 Stripe API 最佳实践
- 不要超出限流阈值,重试时采用指数退避
- 用 Webhook 做事件驱动更新,而不是轮询
代码质量
- 生产构建中不得出现控制台错误或警告
- 提交前移除所有调试日志
- 处理所有边界情况(空状态、数据缺失、网络故障)
- 遵循 Stripe 组件库的模式,保持 UI 一致
版本管理
- 使用语义化版本(MAJOR.MINOR.PATCH)
- 在版本更新中记录破坏性变更
- 尽可能保持向后兼容
UX 质量
广告
- 禁止广告:你的 App 不得展示任何形式的广告
- 禁止交叉推广:不得在 App 界面中推广其他产品或服务
- 品牌内容:只能展示你自己的品牌标识,不得展示第三方品牌(Brevo 这类集成伙伴除外)
语言与内容
- 术语一致:全 App 使用一致的术语
- 专业语气:与 Stripe Dashboard 专业、简洁的沟通风格保持一致
- 不用黑话:避免商家看不懂的技术术语
- 拼写检查:确保所有文案没有拼写和语法错误
- 仅限英文:应用市场 App 面向用户的所有文案都必须使用英文
确认对话框
对破坏性或影响较大的操作,必须要求用户确认:
// Good: Confirm before destructive actionsconst handleDisconnect = async () => { const confirmed = await showConfirmation({ title: 'Disconnect Brevo Integration', message: 'This will stop syncing customer data to Brevo. You can reconnect at any time.', confirmLabel: 'Disconnect', cancelLabel: 'Cancel', destructive: true, });
if (confirmed) { await disconnectIntegration(); }};需要确认的操作:
- 断开集成
- 删除已同步的数据
- 修改影响数据流的设置
- 把配置重置为默认值
加载状态
异步操作必须始终显示加载指示:
// Good: Show loading state during data fetchconst CustomerSyncStatus = () => { const { data, isLoading, error } = useSyncStatus();
if (isLoading) { return <Spinner label="Loading sync status..." />; }
if (error) { return <Banner type="critical" title="Failed to load sync status"> {error.message} </Banner>; }
return <SyncStatusDisplay data={data} />;};要求:
- 数据加载期间显示加载动画或骨架屏
- 表单提交期间禁用按钮
- 长时间运行的操作要显示进度指示
- 加载时绝不能出现空白页面
错误提示
提供清晰、可操作的错误提示:
// Bad: Generic error"Something went wrong"
// Good: Specific and actionable"Unable to sync customer data to Brevo. Please verify your Brevo API keyin Settings and try again."错误提示准则:
- 用平实的语言说明发生了什么
- 给出用户可以采取的具体解决动作
- 提供重试失败操作的入口
- 记录详细的错误信息用于排查(不展示给用户)
- 需要时附上错误码,便于支持团队查询
安全
Secret Store API
所有敏感数据都要用 Stripe 的 Secret Store API 存储:
import { createHttpClient, STRIPE_API_KEY } from '@stripe/ui-extension-sdk/http_client';
// Good: Store secrets using the Secret Store APIconst storeBrevoApiKey = async (apiKey: string) => { const stripe = createHttpClient(STRIPE_API_KEY); await stripe.apps.secrets.create({ name: 'brevo_api_key', payload: apiKey, scope: { type: 'account' }, });};
// Good: Retrieve secrets from the Secret Storeconst getBrevoApiKey = async () => { const stripe = createHttpClient(STRIPE_API_KEY); const secret = await stripe.apps.secrets.find({ name: 'brevo_api_key', scope: { type: 'account' }, }); return secret.payload;};绝不能 把敏感数据存放在:
- 本地存储或会话存储
- Cookie
- URL 参数
- 源码中的硬编码值
- 明文配置文件
加密
- 不要自造加密:不要自行实现加密算法
- 使用 Stripe 内置的安全原语(Secret Store、签名密钥)
- 所有外部 API 调用都走 HTTPS
- 处理前必须校验所有 Webhook 签名
数据处理
- 只申请 App 真正需要的权限
- 除功能必需的部分外,不要存储 Stripe 数据
- 落实与隐私政策一致的数据保留策略
- 提供让用户申请删除数据的途径
法律合规
隐私政策
你的 App 必须有一份可公开访问的隐私政策,涵盖:
- App 从 Stripe 收集哪些数据
- 数据如何存储、处理和共享
- 数据保留与删除策略
- 用户对自身数据享有的权利
- 隐私相关咨询的联系方式
- 对适用法规的合规情况(GDPR、CCPA 等)
服务条款
- 为你的 App 提供清晰的服务条款
- 不得包含与 Stripe 服务条款冲突的内容
- 明确写出任何使用限制或约束
监管合规
- 遵守所有适用的数据保护法规
- 签署合适的数据处理协议
- 支持数据可携带和删除请求
- 保留数据访问与处理的审计日志
审核流程时间线
| 阶段 | 时长 |
|---|---|
| 首次提交 | 5-10 个工作日 |
| 修订复审 | 3-7 个工作日 |
| 最终批准 | 1-2 个工作日 |
| 上架发布 | 批准后立即生效 |
Tip
把所有审核反馈在一次修订中全部处理完,避免多轮审核。对于发现的每个问题,Stripe 团队都会给出具体、可操作的反馈。
常见拒绝原因
- 缺少错误处理,App 在网络错误或数据异常时崩溃
- 加载状态不足,取数期间出现空白页面
- 定价不清晰,展示页面没有完整披露价格
- 权限过度,申请了 App 并不需要的权限
- 沙箱模式不可用,App 在测试模式下无法运行
- 安全问题,把密钥存放在 Secret Store API 之外
- 缺少隐私政策,没有可访问的隐私政策 URL
- 功能不完整,存在 “即将推出” 的功能或占位内容