inflow-payments
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInFlow Payments Integration
InFlow 支付集成
InFlow is a stablecoin payment platform. Sellers (merchants, agents) request payments from consumers; consumers approve via mobile/email/SMS; settlements happen on-chain. Consumers can pre-configure policies that auto-approve requests within budget — enabling 0-click flows for autonomous agents.
This skill integrates InFlow into any project — backend service, full-stack web app, CLI, autonomous agent, or worker — without forcing a specific framework or language. Important: the integration itself is always backend work. Browser code is only ever the optional popup (UX only); every REST call to InFlow and the live exclusively on the server. See the Hard Backend Gate section for the rule and how to handle projects without a backend yet.
inflow.jsINFLOW_API_KEYInFlow是一个稳定币支付平台。卖家(商户、Agent)向消费者发起支付请求;消费者通过手机/邮件/SMS完成授权;结算在链上进行。消费者可预先配置策略,自动批准预算范围内的请求——为自主Agent实现一键式支付流程。
本技能可将InFlow集成到任意项目中——后端服务、全栈Web应用、CLI、自主Agent或Worker——无需强制使用特定框架或语言。重要提示:集成工作始终属于后端范畴。浏览器端代码仅为可选的弹窗(仅负责用户体验);所有对InFlow的REST调用以及必须完全部署在服务器端。请阅读「严格后端限制」章节,了解相关规则以及如何处理尚无后端的项目。
inflow.jsINFLOW_API_KEYWhat InFlow Supports
InFlow支持的功能
| Capability | Endpoint(s) | Use case |
|---|---|---|
| User search | | Find a consumer by email, mobile, or username |
| User registration | | Onboard a new consumer (out-of-band approval) |
| Login | | Authenticate a consumer (out-of-band approval) |
| Payment | | Request a stablecoin payment from a consumer |
| Policies | | Pre-approved spending rules for headless / 0-click flows |
| Webhooks | Inbound | Receive transaction/approval status changes |
| Polling fallback | | Check status without webhooks |
| Wallet read | | Read balances and transaction history |
| Crypto wallets | | Manage on-chain wallet addresses |
| Agentic users | | Create a programmatic account, get an API key |
Currencies: , , , (stablecoins only — no fiat)
Blockchains: , , ,
USDCUSDTEURCPYUSDAPTOSBASESOLANAWORLD| 功能 | 接口 | 使用场景 |
|---|---|---|
| 用户搜索 | | 通过邮箱、手机号或用户名查找消费者 |
| 用户注册 | | 引导新消费者完成注册(需离线授权) |
| 登录 | | 验证消费者身份(需离线授权) |
| 支付 | | 向消费者发起稳定币支付请求 |
| 策略 | | 为无界面/一键式流程预配置消费规则 |
| Webhook | 向你的接口发起入站 | 接收交易/授权状态变更通知 |
| 轮询降级方案 | | 无需Webhook即可查询状态 |
| 钱包查询 | | 查询余额和交易历史 |
| 加密钱包 | | 管理链上钱包地址 |
| Agent用户 | | 创建程序化账户并获取API密钥 |
支持币种:、、、(仅稳定币——不支持法币)
支持区块链:、、、
USDCUSDTEURCPYUSDAPTOSBASESOLANAWORLDWhat This Skill Does NOT Do
本技能不支持的功能
These features are not exposed by the InFlow public API. If the user asks for any of them, stop and tell them they're not supported — do not attempt workarounds:
- Marketplace splits — No field on
splits[]. Multi-recipient payments would need separate sequential requests with no atomic guarantee.PaymentRequest - Refund creation — Transactions can have status , but there's no API to initiate one. Refunds are dashboard-only or out-of-band.
REFUNDED - Webhook URL registration via API — Webhook URLs are configured via the InFlow dashboard. There's no to register them programmatically.
POST /v1/webhooks - OAuth flow for sellers — Despite some legacy documentation referencing "OAuth", consumer authentication is entirely SDK-mediated. There's no OAuth dance for the integrating seller.
以下功能未在InFlow公开API中开放。如果用户询问这些功能,请直接告知不支持——不要尝试变通方案:
- 商城拆分支付——中没有
PaymentRequest字段。多收款方支付需要发起独立的连续请求,但无法保证原子性。splits[] - 创建退款——交易状态可显示为,但没有API可发起退款操作。退款仅能通过控制台或离线方式处理。
REFUNDED - 通过API注册Webhook URL——Webhook URL需通过InFlow控制台配置,没有接口支持程序化注册。
POST /v1/webhooks - 卖家OAuth流程——尽管部分旧文档提到"OAuth",但消费者身份验证完全由SDK处理,集成方无需进行OAuth流程。
Defaults & Decision Tree
默认规则与决策树
When the user doesn't specify, use these defaults:
| Question | Default | Why |
|---|---|---|
| Currency | | Most widely-held stablecoin |
| | Required field; email is the minimum useful identifier |
| Display mode | See decision below | Depends on whether a browser is involved |
| Production vs sandbox | Sandbox SDK URL until user confirms | Production SDK URL is not yet documented |
Display mode: if the consumer is interacting with a browser at the moment of payment (and the page can load ). for everything else: server-to-server, autonomous agents, scheduled jobs, AI workers.
FULLinflow.jsHEADLESSWebhook vs polling: Webhooks for production. Polling only for local development, scripts, or anything without a public HTTPS endpoint.
User identification: A payment must be addressed to a known . The agent must either:
userId- Get the from the user (if they already know it), OR
userId - Search by email/mobile/username via , OR
POST /v1/users/search - Register a new consumer if the search returns 404
Always do user identification BEFORE creating a payment request.
当用户未明确指定时,使用以下默认值:
| 问题 | 默认值 | 原因 |
|---|---|---|
| 币种 | | 持有量最广泛的稳定币 |
| | 必填字段;邮箱是最基础的有效标识符 |
| 展示模式 | 见下方决策逻辑 | 取决于支付时是否涉及浏览器交互 |
| 生产环境 vs 沙箱环境 | 沙箱SDK URL(直到用户确认) | 生产环境SDK URL尚未公开 |
展示模式:如果支付时消费者正在与浏览器交互(且页面可加载),则使用模式。其他场景(服务器间调用、自主Agent、定时任务、AI Worker)均使用模式。
inflow.jsFULLHEADLESSWebhook vs 轮询:生产环境使用Webhook。仅在本地开发、脚本或无公开HTTPS接口的场景下使用轮询。
用户身份识别:支付请求必须指向已知的。Agent需执行以下操作之一:
userId- 从用户处获取(如果用户已知),或者
userId - 通过接口按邮箱/手机号/用户名搜索,或者
POST /v1/users/search - 如果搜索返回404,则注册新消费者
必须先完成用户身份识别,再创建支付请求。
🛑 Hard Backend Gate (Read Before ANY Code)
🛑 严格后端限制(编写代码前必读)
InFlow integration is always backend work. The is a merchant key that must never reach a browser. There is no exception, demo mode, or "just for now" carve-out.
INFLOW_API_KEYInFlow集成始终属于后端工作。是商户密钥,绝对不能暴露到浏览器端。没有例外、演示模式或"暂时处理"的余地。
INFLOW_API_KEYMandatory gate
强制限制
Before writing any InFlow HTTP call, you MUST be able to name the single server-only surface where will be set. Acceptable surfaces:
X-API-Key- An Express / Fastify / Koa / Hono / Hapi route handler
- A Next.js Route Handler () or Server Action — NOT a Client Component
app/api/.../route.ts - A SvelteKit /
+server.ts— NOT a+page.server.tscomponent+page.svelte - A Nuxt /
server/api/*.ts— NOT a Vue component or composableserver/routes/*.ts - A Remix /
loader— NOT a route component bodyaction - A serverless function: Vercel Function, Netlify Function, Cloudflare Worker, AWS Lambda, etc.
- A Python / Go / Rust / .NET / Java HTTP service
- A standalone backend script or worker (no browser involved)
If the project does NOT have any such surface — for example, a pure Vite + React SPA, a static site, a Storybook setup, a Chrome extension popup — STOP. Tell the user they need a backend surface for the API key, even if it's a single-file serverless function or a 30-line Express server. Offer to scaffold one. Do not proceed until the user agrees and the backend surface exists.
在编写任何InFlow HTTP调用之前,你必须能够明确指定仅在服务器端存储的位置。允许的位置包括:
X-API-Key- Express / Fastify / Koa / Hono / Hapi路由处理器
- Next.js路由处理器()或Server Action——不能是客户端组件
app/api/.../route.ts - SvelteKit的/
+server.ts——不能是+page.server.ts组件+page.svelte - Nuxt的/
server/api/*.ts——不能是Vue组件或组合式函数server/routes/*.ts - Remix的/
loader——不能是路由组件主体action - 无服务器函数:Vercel Function、Netlify Function、Cloudflare Worker、AWS Lambda等
- Python / Go / Rust / .NET / Java HTTP服务
- 独立后端脚本或Worker(不涉及浏览器)
如果项目没有上述任何服务器端环境——例如纯Vite + React单页应用、静态站点、Storybook环境、Chrome扩展弹窗——立即停止。告知用户需要为API密钥准备后端环境,哪怕是一个单文件无服务器函数或30行的Express服务器。在用户同意并搭建好后端环境之前,不要继续操作。
Framework-specific footguns (key-leak mechanics)
框架常见陷阱(密钥泄露途径)
These are real, common ways merchant keys end up in browsers. Refuse them all.
Next.js:
- referenced inside a
process.env.INFLOW_API_KEYcomponent is'use client'at runtime — Next.js does NOT bundle non-undefinedenv vars into client code. The bug surfaces as a broken request with no auth header.NEXT_PUBLIC_ - The disaster happens when an agent "fixes" this by renaming the var to
undefined. That prefix tells the bundler to inline the value into the client bundle → the key is now shipped to every visitor.NEXT_PUBLIC_INFLOW_API_KEY - NEVER prefix with
INFLOW_API_KEY. The correct fix is to move the call to a Server Component, Route Handler (NEXT_PUBLIC_), or Server Action — never to make the key public.app/api/.../route.ts
Vite (React, Vue, Svelte, Solid, etc.):
- is
import.meta.env.INFLOW_API_KEYunless prefixed withundefined. Some agents "fix" this by renaming toVITE_→ Vite then inlines the key into the client bundle and ships it to every visitor.VITE_INFLOW_API_KEY - NEVER prefix with
INFLOW_API_KEY. Vite has no server runtime by itself. If you need a backend, the user has to add one (Express, Fastify, or pair with a serverless function).VITE_
SvelteKit:
- Components and files run in the browser. Use
+page.svelte,+server.ts, or+page.server.ts(the$lib/server/*directory is enforced as server-only by the bundler).server
Nuxt:
- Vue components and composables run in the browser. Use route handlers or
server/api/*. Never readserver/utils/*from aINFLOW_API_KEYblock in a<script setup>file..vue
Astro / Remix / Qwik / Solid Start:
- All have a server/client split. The rule is the same: is read only inside the framework's server boundary (loader, action, server route, etc.), never in component code.
INFLOW_API_KEY
以下是商户密钥泄露到浏览器的真实常见场景,需全部拒绝:
Next.js:
- 在组件中引用
'use client'会在运行时返回process.env.INFLOW_API_KEY——Next.js不会将非undefined前缀的环境变量打包到客户端代码中。该问题表现为请求因缺少授权头而失败。NEXT_PUBLIC_ - 当Agent试图通过将变量重命名为来"修复"
NEXT_PUBLIC_INFLOW_API_KEY问题时,灾难就会发生。该前缀会告诉打包工具将值内联到客户端代码中→ 密钥会被发送给每一位访客。undefined - 绝对不要给添加
INFLOW_API_KEY前缀。正确的修复方式是将调用移至Server Component、路由处理器(NEXT_PUBLIC_)或Server Action——绝对不要将密钥公开。app/api/.../route.ts
Vite(React、Vue、Svelte、Solid等):
- 仅在添加
import.meta.env.INFLOW_API_KEY前缀时才会生效。部分Agent会通过重命名为VITE_来"修复"问题→ Vite会将密钥内联到客户端代码中并发送给每一位访客。VITE_INFLOW_API_KEY - 绝对不要给添加
INFLOW_API_KEY前缀。Vite本身没有服务器运行时。如果需要后端,用户必须添加一个(Express、Fastify或搭配无服务器函数)。VITE_
SvelteKit:
- 组件和文件在浏览器中运行。请使用
+page.svelte、+server.ts或+page.server.ts(打包工具会强制$lib/server/*目录仅在服务器端运行)。server
Nuxt:
- Vue组件和组合式函数在浏览器中运行。请使用路由处理器或
server/api/*。绝对不要在server/utils/*文件的.vue块中读取<script setup>。INFLOW_API_KEY
Astro / Remix / Qwik / Solid Start:
- 所有框架都有服务器/客户端拆分规则。规则一致:仅能在框架的服务器边界内读取(loader、action、服务器路由等),绝对不能在组件代码中读取。
INFLOW_API_KEY
The "just a demo" trap
"只是演示"的陷阱
If the user says "this is just a demo", "just for testing", "we'll add the backend later", "just for now", or anything similar — the rule still applies. Embedded merchant keys leak via:
- Git history (especially after a "fix")
git push --force - Browser devtools (anyone can open them)
- Browser extensions (they read your scripts)
- Error reports / crash dumps shared in tickets
- Screenshots posted in Slack / GitHub / Stack Overflow
- Build artifacts uploaded to CDNs
- Deployed preview URLs that get crawled
A "temporary" key in the browser is a permanent key on the internet. There is no safe short-term embed.
For a quick demo, the right move is still a backend — just a small one. A 20-line Express script, a single Vercel Function, or a Cloudflare Worker. All take less time than the apology email after a key leak.
如果用户说*"这只是演示"、"只是测试用"、"我们之后再添加后端"、"暂时先用着"*或类似话语——规则仍然适用。嵌入到浏览器中的商户密钥会通过以下途径泄露:
- Git历史(尤其是"修复"之后)
git push --force - 浏览器开发者工具(任何人都能打开)
- 浏览器扩展(会读取脚本内容)
- 工单中分享的错误报告/崩溃日志
- Slack / GitHub / Stack Overflow中发布的截图
- 上传到CDN的构建产物
- 被爬虫抓取的预览部署URL
浏览器中的"临时"密钥会永久暴露在互联网上。没有安全的短期嵌入方式。
对于快速演示,正确的做法仍然是搭建后端——只是一个小型后端即可。20行的Express脚本、单个Vercel Function或Cloudflare Worker都可以。搭建这些的时间比密钥泄露后的道歉邮件要短得多。
Backend-Only Fast Path (No Browser, No Frontend)
纯后端快速路径(无浏览器、无前端)
If the user is integrating InFlow into a pure backend, API, agent, worker, or service — skip the browser/SDK material entirely and follow this short path. This is the most common backend integration shape.
Order of operations:
- Set env vars (Step 1) — , optionally
INFLOW_API_KEYINFLOW_WEBHOOK_SECRET - Identify the consumer (Step 2) — with email/mobile/username → get
POST /v1/users/searchuserId - Create the payment with (Step 3) — pass
display: HEADLESSif you have one for 0-click; otherwise the consumer gets a mobile/email approval promptpolicyId - Persist your correlation key — store so the webhook handler can look up the right order. The webhook payload only carries InFlow's IDs; you must map them back to your business object.
{ yourOrderId, requestId, transactionId? } - Wait for confirmation — either:
- Webhook handler (Step 5) — recommended for production. Verify HMAC, idempotency by , fulfill on
eventId(with the discriminator check)event.data.status === "PAID" - OR polling (Step 6) — for scripts, batch jobs, local dev. Call until status leaves
GET /v1/requests/{requestId}PENDING
- Webhook handler (Step 5) — recommended for production. Verify HMAC, idempotency by
Skip: Step 4 (frontend SDK), the full-stack happy path diagram below, anything mentioning or browsers.
inflow.jsFor autonomous agents that need 0-click headless payments without consumer interaction per transaction, also implement Step 7 (Policies) and attach to every payment request.
policyId如果用户要将InFlow集成到纯后端、API、Agent、Worker或服务中——完全跳过浏览器/SDK相关内容,遵循以下简化流程。这是最常见的后端集成模式。
操作顺序:
- 设置环境变量(步骤1)——,可选
INFLOW_API_KEYINFLOW_WEBHOOK_SECRET - 识别消费者(步骤2)——调用接口,传入邮箱/手机号/用户名→获取
POST /v1/users/searchuserId - 创建模式的支付请求(步骤3)——如果有实现一键式支付的策略,传入
display: HEADLESS;否则消费者会收到手机/邮箱授权提示policyId - 持久化关联密钥——存储,以便Webhook处理器能找到对应的订单。Webhook payload仅包含InFlow的ID;你必须将其映射回业务对象。
{ yourOrderId, requestId, transactionId? } - 等待确认——选择以下方式之一:
- Webhook处理器(步骤5)——生产环境推荐。验证HMAC签名,通过实现幂等性,当
eventId时完成订单(需进行判别检查)event.data.status === "PAID" - 或轮询(步骤6)——适用于脚本、批量任务、本地开发。调用直到状态不再是
GET /v1/requests/{requestId}PENDING
- Webhook处理器(步骤5)——生产环境推荐。验证HMAC签名,通过
跳过内容:步骤4(前端SDK)、下方的全栈流程示意图、所有提及或浏览器的内容。
inflow.js对于自主Agent:如果需要无需每次交易都经过消费者交互的一键式无界面支付,还需实现步骤7(策略),并将附加到每个支付请求中。
policyIdOrder Correlation (Backend Pattern)
订单关联(后端模式)
A common bug in payment integrations: the webhook arrives but the handler can't figure out which of your orders it belongs to. The InFlow webhook payload contains InFlow's IDs (, , ) but none of your business IDs. You must store the mapping yourself at payment creation time.
requestIdtransactionIdapprovalIdMinimum mapping table (in your DB / store / cache):
| Your column | Source |
|---|---|
| Your business object — the thing being purchased |
| Returned from |
| Returned later in webhook payload ( |
| Your local state machine: |
| Audit trail |
At payment creation: insert a row with + , status .
your_order_idinflow_request_idpendingAt webhook receipt: look up the row by (use or correlate via if is an ; use once it appears in a ). Update status. Fulfill the order.
inflow_request_idevent.data.approvalIdrequestIddataApprovalResponseevent.data.transactionIdTransactionResponseIdempotency: also store processed s separately so you don't double-fulfill on retries (InFlow may resend the same event for up to 72 hours).
event.eventId支付集成中的常见问题:Webhook到达后,处理器无法确定对应的订单。InFlow Webhook payload包含InFlow的ID(、、),但不包含任何业务ID。你必须在创建支付请求时自行存储映射关系。
requestIdtransactionIdapprovalId最小映射表(存储在你的数据库/存储/缓存中):
| 你的字段 | 来源 |
|---|---|
| 你的业务对象——即购买的商品/服务 |
| |
| 后续Webhook payload中的 |
| 你的本地状态机: |
| 审计日志 |
创建支付请求时:插入一条包含 + 的记录,状态设为。
your_order_idinflow_request_idpending收到Webhook时:通过查找记录(如果是,则使用或通过关联;如果是,则使用)。更新状态并完成订单。
inflow_request_iddataApprovalResponseevent.data.approvalIdrequestIdTransactionResponseevent.data.transactionId幂等性:还需单独存储已处理的,避免因重试导致重复完成订单(InFlow可能在72小时内重发同一事件)。
event.eventIdHappy Path: Add Checkout to a Web App
常见场景:为Web应用添加结账功能
This is the most common request. End-to-end recipe for "I want to accept InFlow payments at checkout":
┌──────────────────────────────────────────────────────────────────┐
│ Frontend (browser) │
├──────────────────────────────────────────────────────────────────┤
│ 1. Collect consumer email at checkout │
│ 2. Click "Pay with InFlow" → POST to YOUR /api/inflow/checkout │
│ 3. Receive { requestId } from your backend │
│ 4. Render popup: new InFlow.Request(requestId).render({...}) │
│ 5. statusCallback fires when consumer approves │
│ 6. Show "processing..." (DO NOT fulfill yet) │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Backend (your /api/inflow/checkout endpoint) │
├──────────────────────────────────────────────────────────────────┤
│ 1. Receive { email, amount } from frontend │
│ 2. POST /v1/users/search { email } → get userId │
│ (if 404 → POST /v1/requests/register first) │
│ 3. POST /v1/requests/payment { │
│ userId, amount, currency: "USDC", │
│ display: "FULL", userDetails: ["EMAIL"] │
│ } │
│ 4. Return { requestId } to frontend │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Backend (your /api/webhooks/inflow endpoint) │
├──────────────────────────────────────────────────────────────────┤
│ 1. Receive POST from InFlow with x-inflow-signature header │
│ 2. Verify HMAC-SHA256 signature → 401 if invalid │
│ 3. Check eventId against idempotency store → skip if seen │
│ 4. Fulfill ONLY if ALL three are true: │
│ a. event.type === "TRANSACTION_UPDATED" │
│ b. event.data.transactionId is present │
│ (i.e. data is a TransactionResponse, not Approval) │
│ c. event.data.status === "PAID" │
│ (use INNER data.status, NOT outer event.status) │
│ 5. Return HTTP 200 │
└──────────────────────────────────────────────────────────────────┘Twofields, two meanings. The webhook envelope has an outerstatus(event.status/DELIVERED/FAILED/PENDING— InFlow's delivery state) and the innerDISABLED(the actual transaction state likeevent.data.status/PAID/PENDING). Always checkINSUFFICIENT_FUNDSfor fulfillment decisions. See Step 5 for details.event.data.status
The three things the user MUST do manually:
- Get an (from InFlow dashboard, or create an agentic user — see "Agentic User Setup" below)
INFLOW_API_KEY - Register the webhook URL in the InFlow dashboard (no API for this)
https://yourdomain.com/api/webhooks/inflow - Get the from the InFlow dashboard after registering the URL
INFLOW_WEBHOOK_SECRET
After implementing the integration, summarize these manual steps prominently.
这是最常见的需求。以下是"我想在结账时接收InFlow支付"的端到端实现方案:
┌──────────────────────────────────────────────────────────────────┐
│ 前端(浏览器) │
├──────────────────────────────────────────────────────────────────┤
│ 1. 在结账页面收集消费者邮箱 │
│ 2. 点击"使用InFlow支付" → 向你的/api/inflow/checkout发起POST请求 │
│ 3. 从后端接收{ requestId } │
│ 4. 渲染弹窗:new InFlow.Request(requestId).render({...}) │
│ 5. 消费者完成授权后触发statusCallback │
│ 6. 显示"处理中..."(**不要立即完成订单**) │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 后端(你的/api/inflow/checkout接口) │
├──────────────────────────────────────────────────────────────────┤
│ 1. 从前端接收{ email, amount } │
│ 2. 调用POST /v1/users/search { email } → 获取userId │
│ (如果返回404 → 先调用POST /v1/requests/register) │
│ 3. 调用POST /v1/requests/payment { │
│ userId, amount, currency: "USDC", │
│ display: "FULL", userDetails: ["EMAIL"] │
│ } │
│ 4. 将{ requestId }返回给前端 │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 后端(你的/api/webhooks/inflow接口) │
├──────────────────────────────────────────────────────────────────┤
│ 1. 接收InFlow的POST请求,包含x-inflow-signature请求头 │
│ 2. 验证HMAC-SHA256签名 → 无效则返回401 │
│ 3. 检查eventId是否在幂等性存储中 → 已处理则跳过 │
│ 4. 仅当以下三个条件全部满足时才完成订单: │
│ a. event.type === "TRANSACTION_UPDATED" │
│ b. event.data.transactionId存在 │
│ (即data是TransactionResponse,而非Approval) │
│ c. event.data.status === "PAID" │
│ (使用内层的data.status,而非外层的event.status) │
│ 5. 返回HTTP 200 │
└──────────────────────────────────────────────────────────────────┘两个字段,两种含义。Webhook信封包含外层status(event.status/DELIVERED/FAILED/PENDING——InFlow的投递状态)和内层DISABLED(实际交易状态,如event.data.status/PAID/PENDING)。必须检查INSUFFICIENT_FUNDS来决定是否完成订单。详见步骤5。event.data.status
用户必须手动完成的三件事:
- 获取(从InFlow控制台,或创建Agent用户——见下方"Agent用户设置")
INFLOW_API_KEY - 在InFlow控制台中注册Webhook URL (无API支持此操作)
https://yourdomain.com/api/webhooks/inflow - 注册URL后,从InFlow控制台获取
INFLOW_WEBHOOK_SECRET
完成集成后,请突出总结这些手动步骤。
Reference Material
参考资料
This skill ships with three reference documents in . Read them when you need details beyond what's in this file:
references/- — Platform concepts, approval model, FULL vs HEADLESS display modes
references/overview.md - — 8 worked-out integration flows with HTTP examples
references/flows.md - — Every endpoint, every schema, every enum value
references/api-reference.md
When the user asks something specific (e.g. "how do I list policies?", "what does the webhook payload look like?"), look it up in the references rather than guessing.
本技能附带三份参考文档,位于目录下。当需要本文件之外的详细信息时,请查阅这些文档:
references/- ——平台概念、授权模型、FULL与HEADLESS展示模式
references/overview.md - ——8个完整的集成流程示例及HTTP调用示例
references/flows.md - ——所有接口、所有Schema、所有枚举值
references/api-reference.md
当用户询问特定问题(例如"如何列出策略?"、"Webhook payload是什么样的?")时,请查阅参考资料,不要猜测。
Implementation Guide
实现指南
Prerequisites
前置条件
Before writing any code:
- Read the project — detect language and framework via ,
package.json,requirements.txt,go.mod, etc. Use whatever HTTP client and web framework already exists. Do not impose Express, Next.js, React, or any specific framework.Cargo.toml - Pass the Hard Backend Gate (see the "🛑 Hard Backend Gate" section earlier in this file) — name the server-only surface where the API key will live. If there isn't one, scaffold one (with the user's agreement) before continuing.
- Confirm the user has an API key — if not, walk them through the agentic user setup at the bottom of this file.
- Confirm the project type — pure backend / fullstack web app / CLI / agent / worker. Pure-frontend projects are NOT a valid type — see the Hard Backend Gate.
- Pure backend → Server payment + webhook (or polling)
- Fullstack / web app → Server payment + frontend SDK + webhook
- CLI / agent / worker → Headless payment + webhook (or polling) + maybe policies for 0-click
编写代码之前:
- 了解项目——通过、
package.json、requirements.txt、go.mod等文件检测语言和框架。使用项目已有的HTTP客户端和Web框架,不要强制使用Express、Next.js、React或其他特定框架。Cargo.toml - 通过严格后端限制检查(见前文「🛑 严格后端限制」章节)——明确指定存储API密钥的服务器端位置。如果没有,需在用户同意后搭建一个,再继续操作。
- 确认用户已有API密钥——如果没有,引导用户完成下方的Agent用户设置。
- 确认项目类型——纯后端/全栈Web应用/CLI/Agent/Worker。纯前端项目不属于有效类型——见严格后端限制。
- 纯后端 → 服务器支付 + Webhook(或轮询)
- 全栈/Web应用 → 服务器支付 + 前端SDK + Webhook
- CLI/Agent/Worker → 无界面支付 + Webhook(或轮询) + 可能需要策略实现一键式支付
Step 1: Set Up Environment Variables
步骤1:设置环境变量
Add these to the project's existing env file (, , etc. — match the project's convention). Add to too.
.env.env.local.env.exampleundefined将以下变量添加到项目现有的环境文件中(、等——遵循项目约定)。同时添加到中。
.env.env.local.env.exampleundefinedRequired for any InFlow integration
任何InFlow集成都需要
INFLOW_API_KEY=<your-private-key>
INFLOW_API_KEY=<你的私有密钥>
Required if you handle webhooks
处理Webhook时需要
INFLOW_WEBHOOK_SECRET=<your-webhook-secret>
INFLOW_WEBHOOK_SECRET=<你的Webhook密钥>
Optional: defaults to https://api.inflowpay.ai
可选:默认值为https://api.inflowpay.ai
INFLOW_API_BASE_URL=https://api.inflowpay.ai
INFLOW_API_BASE_URL=https://api.inflowpay.ai
Make sure `.env` and `.env.local` are in `.gitignore`.
**Critical:** `INFLOW_API_KEY` is server-side only. Never embed it in frontend code, never expose it via a public route, never log it.
确保`.env`和`.env.local`已添加到`.gitignore`中。
**关键提示**:`INFLOW_API_KEY`仅能在服务器端使用。绝对不要嵌入到前端代码中,不要通过公开路由暴露,不要记录日志。Step 2: Find or Create the Consumer
步骤2:查找或创建消费者
A payment must be addressed to a . If the user doesn't know the consumer's , you must look it up first.
userIduserIdSearch by email (or mobile / username):
http
POST https://api.inflowpay.ai/v1/users/search
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{ "email": "alice@example.com" }On match (200):
json
{ "userId": "8a5c2948-9e08-439e-a7a6-9f0ee335f566" }On no match (404): initiate registration:
http
POST https://api.inflowpay.ai/v1/requests/register
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"display": "FULL",
"userDetails": ["EMAIL", "NAME"]
}⚠️ API quirk:listsRegisterRequestas optional (onlyuserIdanddisplayare required per the OpenAPI spec), but its semantics for a true new-user registration flow are not documented. Do not invent a UUID. Try the call withoutuserDetailsfirst; if the API rejects it, the user must obtain a provisionaluserIdfrom InFlow support or check vendor docs. Treat this as vendor-ambiguous and surface the ambiguity to the user — do not silently work around it.userId
This returns an with a . Hand the to the frontend SDK to render the registration popup. After approval, the consumer is registered and can be searched again.
ApprovalResponserequestIdrequestIdSearch field rules:
- — RFC email format
email - — E.164 format like
mobile+15551234567 - — 3-16 chars, alphanumeric +
username-_
userDetailsBIRTHDATEDEPOSIT_ADDRESSESEMAILMOBILENAMENATIONAL_IDPHYSICAL_ADDRESSUSERNAMEEMAIL支付请求必须指向。如果用户不知道消费者的,必须先进行查找。
userIduserId按邮箱(或手机号/用户名)搜索:
http
POST https://api.inflowpay.ai/v1/users/search
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{ "email": "alice@example.com" }匹配成功(200):
json
{ "userId": "8a5c2948-9e08-439e-a7a6-9f0ee335f566" }匹配失败(404): 发起注册请求:
http
POST https://api.inflowpay.ai/v1/requests/register
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"display": "FULL",
"userDetails": ["EMAIL", "NAME"]
}⚠️ API特性:将RegisterRequest列为可选(根据OpenAPI规范,仅userId和display为必填),但针对新用户注册流程的语义尚未文档化。不要自行生成UUID。先尝试不传入userDetails调用接口;如果API拒绝,用户必须从InFlow支持团队获取临时userId或查阅厂商文档。请将此不确定性告知用户——不要默默变通。userId
该接口会返回包含的。将传递给前端SDK以渲染注册弹窗。消费者完成授权后,即可再次搜索到该用户。
requestIdApprovalResponserequestId搜索字段规则:
- ——符合RFC标准的邮箱格式
email - ——E.164格式,如
mobile+15551234567 - ——3-16字符,仅包含字母、数字及
username-_
userDetailsBIRTHDATEDEPOSIT_ADDRESSESEMAILMOBILENAMENATIONAL_IDPHYSICAL_ADDRESSUSERNAMEEMAILStep 3: Create a Payment Request
步骤3:创建支付请求
http
POST https://api.inflowpay.ai/v1/requests/payment
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"userId": "<consumer-uuid-from-Step-2>",
"amount": 99.99,
"currency": "USDC",
"display": "FULL",
"userDetails": ["EMAIL"]
}Response (200):
json
{
"requestId": "<uuid>",
"type": "PAYMENT",
"status": "PENDING"
}Required fields: (≥ 0.01), , , .
Optional: , (for auto-approval via a pre-existing policy).
amountcurrencydisplayuserDetailsuserIdpolicyIdAmount format: Plain decimal in major units of the chosen stablecoin. means 99.99 USDC (≈ $99.99). No cents/minor units.
99.99Adapt the HTTP call to the user's stack — read the project and use whatever HTTP client is already in use. The exact code shape depends on the language (Node fetch, Python requests, Go net/http, etc.).
Error handling:
- 4xx → user error (missing field, invalid format, user not found). Return the error to the caller, don't retry.
- 5xx / network → transient. Retry with exponential backoff (max 3 attempts) before failing the checkout.
After getting , the next step depends on the display mode:
requestId- → hand
FULLto the frontend SDK (Step 4)requestId - → wait for the webhook (Step 5) or poll
HEADLESS(Step 6)GET /v1/requests/{requestId}
http
POST https://api.inflowpay.ai/v1/requests/payment
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"userId": "<步骤2获取的消费者UUID>",
"amount": 99.99,
"currency": "USDC",
"display": "FULL",
"userDetails": ["EMAIL"]
}响应(200):
json
{
"requestId": "<UUID>",
"type": "PAYMENT",
"status": "PENDING"
}必填字段: (≥ 0.01)、、、。
可选字段: 、(用于通过已有策略自动授权)。
amountcurrencydisplayuserDetailsuserIdpolicyId金额格式: 所选稳定币的主单位十进制数。表示99.99 USDC(≈ 99.99美元)。不支持分/辅单位。
99.99适配用户技术栈——了解项目并使用已有的HTTP客户端。具体代码形式取决于语言(Node fetch、Python requests、Go net/http等)。
错误处理:
- 4xx → 用户错误(缺失字段、格式无效、用户不存在)。将错误返回给调用方,不要重试。
- 5xx / 网络错误 → 临时错误。使用指数退避重试(最多3次)后再终止结账流程。
获取后,下一步取决于展示模式:
requestId- → 将
FULL传递给前端SDK(步骤4)requestId - → 等待Webhook(步骤5)或轮询
HEADLESS(步骤6)GET /v1/requests/{requestId}
Step 4: Frontend SDK (inflow.js
) — for display: FULL
inflow.jsdisplay: FULL步骤4:前端SDK(inflow.js
)——适用于display: FULL
模式
inflow.jsdisplay: FULLFor browser-based flows. The frontend loads , gets a from the backend, and renders a popup.
inflow.jsrequestIdLoad the SDK:
html
<script src="https://sandbox.inflowpay.ai/sdk/inflow.js"></script>⚠️ This is the sandbox URL. The production URL is not yet publicly documented. Before deploying to production, the user should confirm the production SDK URL with InFlow.
Render a request:
js
// Get the requestId from your backend (which calls POST /v1/requests/{login|register|payment|...})
const requestId = await fetchRequestIdFromYourBackend();
const request = new InFlow.Request(requestId);
request.render({
statusCallback: (status) => {
// status.status is one of: PENDING, APPROVED, DECLINED, EXPIRED, CANCELLED
if (status.status === InFlow.STATUS.APPROVED) {
// SDK indicated user approved. Show "processing..."
// DO NOT fulfill the order here — wait for the webhook.
}
}
});Same pattern works for login, register, payment, and details requests. Only the backend endpoint that produces the differs.
requestIdAdapt the surrounding markup to the user's framework — wrap in a React/Vue/Svelte component if needed. The SDK itself is framework-agnostic.
适用于基于浏览器的流程。前端加载,从后端获取并渲染弹窗。
inflow.jsrequestId加载SDK:
html
<script src="https://sandbox.inflowpay.ai/sdk/inflow.js"></script>⚠️ 这是沙箱环境URL。生产环境URL尚未公开。部署到生产环境前,用户需与InFlow确认生产环境SDK URL。
渲染请求:
js
// 从你的后端获取requestId(后端调用POST /v1/requests/{login|register|payment|...}生成)
const requestId = await fetchRequestIdFromYourBackend();
const request = new InFlow.Request(requestId);
request.render({
statusCallback: (status) => {
// status.status可选值:PENDING, APPROVED, DECLINED, EXPIRED, CANCELLED
if (status.status === InFlow.STATUS.APPROVED) {
// SDK提示用户已授权。显示"处理中..."
// **不要在此处完成订单**——等待Webhook通知。
}
}
});相同模式适用于登录、注册、支付和详情请求。仅生成的后端接口不同。
requestId适配用户框架——如果需要,可封装到React/Vue/Svelte组件中。SDK本身与框架无关。
Step 5: Webhook Handler
步骤5:Webhook处理器
InFlow delivers signed events to your registered webhook URL.
🚨 CRITICAL MANUAL STEP: The webhook URL must be registered in the InFlow dashboard by the user — there is no API for this. After implementing the handler, tell the user explicitly:"Go to the InFlow dashboard, navigate to webhooks, register(or your equivalent URL), and copy the webhook secret into yourhttps://yourdomain.com/api/webhooks/inflowenv var. Until you do this, no events will be delivered."INFLOW_WEBHOOK_SECRET
For local testing, suggest ngrok or similar to expose over HTTPS.
localhostWebhook payload shape — note the two fields:
statusjson
{
"eventId": "<uuid>",
"webhookId": "<uuid>",
"type": "TRANSACTION_UPDATED",
"status": "DELIVERED", ← OUTER: InFlow's delivery state. Ignore for fulfillment.
"data": {
"transactionId": "<uuid>",
"approvalId": "<uuid>",
"amount": 99.99,
"currency": "USDC",
"blockchain": "SOLANA",
"status": "PAID", ← INNER: actual transaction state. Use this for fulfillment.
"transactionHash": "0x...",
"created": "2026-01-01T00:00:00.000Z"
},
"created": "2026-01-01T00:00:00.000Z",
"delivered": "2026-01-01T00:00:01.000Z"
}Critical disambiguation: the envelope has TWOfields:status
(outer) — InFlow's webhook delivery state:event.status/PENDING/DELIVERED/FAILED. This tells you whether InFlow successfully delivered the event. Don't branch on this for business logic.DISABLED (inner) — the actual transaction or approval state:event.data.status,PAID,INITIATED,PENDING,INSUFFICIENT_FUNDS,APPROVED, etc. This is what you check for fulfillment.DECLINED
Event types: ,
TRANSACTION_CREATEDTRANSACTION_UPDATEDThe field is a discriminated union:
data- If it has and
requestId(LOGIN/PAYMENT/etc.) → it's antypeApprovalResponse - If it has ,
transactionId, andblockchain→ it's atransactionHashTransactionResponse
Only fulfill orders when ALL of these are true: , the field is shaped as a (presence of is the simplest discriminator), and . Do not generalize to "any TRANSACTION_* event with status PAID" — an payload may also have a field (//etc.) and using it for fulfillment will crash or misfire.
event.type === "TRANSACTION_UPDATED"dataTransactionResponsetransactionIdevent.data.status === "PAID"ApprovalResponsestatusAPPROVEDPENDINGdata.status- — payment completed (this is your "fulfill the order" signal)
PAID - ,
INITIATED— in progress, do nothingPENDING - ,
INSUFFICIENT_FUNDS— failed, notify userGENERAL_ERROR - ,
REFUNDED— money was returnedRETURNED
Mandatory: HMAC signature verification. Every webhook is signed with HMAC-SHA256. The signature is in the header. Verify it before processing.
x-inflow-signaturejs
// Generic — adapt to whatever crypto library the project uses.
// Node.js example using built-in crypto module:
import crypto from 'node:crypto';
function verifyInflowWebhook(rawBody, signatureHeader, secret) {
// Guard against missing or malformed header — timingSafeEqual throws on length mismatch
if (typeof signatureHeader !== 'string' || signatureHeader.length === 0) return false;
if (!rawBody || !secret) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
if (expected.length !== signatureHeader.length) return false;
// Constant-time compare to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader),
);
}The same logic applies in any language: HMAC-SHA256 the raw request body using the webhook secret, hex-encode it, compare to the header.
x-inflow-signatureCritical: verify against the raw request body bytes, NOT a re-serialized JSON object. If the framework parses JSON automatically, you must capture the raw body before parsing. The exact mechanism depends on the framework.
Webhook handler responsibilities:
- Verify the signature → reject with HTTP 401 if invalid
- Parse the JSON body
- Check against an idempotency store → skip if already processed (InFlow may retry the same event for up to 72 hours)
eventId - Look up your local order by or
event.data.approvalId(see Order Correlation section above)event.data.transactionId - Branch on the FULL three-condition rule (do not skip any of these):
- Fulfill when ALL of: AND
event.type === "TRANSACTION_UPDATED"is present (it's aevent.data.transactionId, not anTransactionResponse) ANDApprovalResponseevent.data.status === "PAID" - Mark failed when present AND
event.data.transactionIdisevent.data.status/INSUFFICIENT_FUNDS/GENERAL_ERRORRETURNED - Log only for other event types or non-terminal statuses (,
INITIATED, etc.)PENDING - NEVER fulfill on (the OUTER delivery status) — that just means InFlow delivered the webhook successfully
event.status
- Fulfill when ALL of:
- Return HTTP 200 to acknowledge
If the handler doesn't return 200, InFlow keeps retrying with exponential backoff for up to 72 hours.
InFlow会将签名后的事件发送到你注册的Webhook URL。
🚨 关键手动步骤:Webhook URL必须由用户在InFlow控制台中注册——无API支持此操作。完成处理器实现后,请明确告知用户:"请登录InFlow控制台,进入Webhook页面,注册(或你的等效URL),并将Webhook密钥复制到https://yourdomain.com/api/webhooks/inflow环境变量中。完成此操作前,不会收到任何事件通知。"INFLOW_WEBHOOK_SECRET
本地测试时,建议使用ngrok或类似工具将暴露为HTTPS地址。
localhostWebhook payload结构——注意两个字段:
statusjson
{
"eventId": "<UUID>",
"webhookId": "<UUID>",
"type": "TRANSACTION_UPDATED",
"status": "DELIVERED", ← 外层:InFlow的投递状态。不要用于业务逻辑判断。
"data": {
"transactionId": "<UUID>",
"approvalId": "<UUID>",
"amount": 99.99,
"currency": "USDC",
"blockchain": "SOLANA",
"status": "PAID", ← 内层:实际交易状态。用于判断是否完成订单。
"transactionHash": "0x...",
"created": "2026-01-01T00:00:00.000Z"
},
"created": "2026-01-01T00:00:00.000Z",
"delivered": "2026-01-01T00:00:01.000Z"
}关键区分:信封包含两个字段:status
(外层)——InFlow的Webhook投递状态:event.status/PENDING/DELIVERED/FAILED。仅表示InFlow是否成功投递事件,不要用于业务逻辑分支判断。DISABLED (内层)——实际交易或授权状态:event.data.status、PAID、INITIATED、PENDING、INSUFFICIENT_FUNDS、APPROVED等。这是判断是否完成订单的依据。DECLINED
事件类型: 、
TRANSACTION_CREATEDTRANSACTION_UPDATEDdata- 如果包含和
requestId(LOGIN/PAYMENT等)→ 是typeApprovalResponse - 如果包含、
transactionId和blockchain→ 是transactionHashTransactionResponse
仅当以下所有条件满足时才完成订单:,字段为格式(最简单的判别方式是存在),且。不要泛化为"任何TRANSACTION_*事件且状态为PAID"—— payload也可能包含字段(/等),误用会导致崩溃或误触发。
event.type === "TRANSACTION_UPDATED"dataTransactionResponsetransactionIdevent.data.status === "PAID"ApprovalResponsestatusAPPROVEDPENDINGdata.status- ——支付完成(这是"完成订单"的信号)
PAID - 、
INITIATED——处理中,无需操作PENDING - 、
INSUFFICIENT_FUNDS——支付失败,通知用户GENERAL_ERROR - 、
REFUNDED——款项已退回RETURNED
强制要求:HMAC签名验证。每个Webhook都会使用HMAC-SHA256签名。签名位于请求头中。处理前必须验证签名。
x-inflow-signaturejs
// 通用逻辑——适配项目使用的加密库。
// Node.js示例,使用内置crypto模块:
import crypto from 'node:crypto';
function verifyInflowWebhook(rawBody, signatureHeader, secret) {
// 防范缺失或格式错误的请求头——timingSafeEqual在长度不匹配时会抛出异常
if (typeof signatureHeader !== 'string' || signatureHeader.length === 0) return false;
if (!rawBody || !secret) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
if (expected.length !== signatureHeader.length) return false;
// 常量时间比较,防止时序攻击
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader),
);
}任何语言的逻辑一致:使用Webhook密钥对原始请求体进行HMAC-SHA256加密,转为十六进制,与请求头的值对比。
x-inflow-signature关键提示:必须针对原始请求体字节进行验证,而非重新序列化的JSON对象。如果框架自动解析JSON,必须在解析前捕获原始请求体。具体实现方式取决于框架。
Webhook处理器职责:
- 验证签名 → 无效则返回HTTP 401
- 解析JSON请求体
- 检查是否在幂等性存储中 → 已处理则跳过(InFlow可能在72小时内重发同一事件)
eventId - 通过或
event.data.approvalId查找本地订单(见前文「订单关联」章节)event.data.transactionId - 严格遵循三个条件进行分支判断(不要跳过任何一个):
- 完成订单:当且
event.type === "TRANSACTION_UPDATED"存在(是event.data.transactionId而非TransactionResponse)且ApprovalResponseevent.data.status === "PAID" - 标记为失败:当存在且
event.data.transactionId为event.data.status/INSUFFICIENT_FUNDS/GENERAL_ERRORRETURNED - 仅记录日志:其他事件类型或非终态状态(、
INITIATED等)PENDING - 绝对不要根据(外层投递状态)完成订单——仅表示InFlow成功投递了Webhook
event.status
- 完成订单:当
- 返回HTTP 200确认接收
如果处理器未返回200,InFlow会使用指数退避重试,最多持续72小时。
Step 6: Polling (Webhook Alternative)
步骤6:轮询(Webhook替代方案)
If a webhook listener isn't possible (local dev, batch jobs, simple scripts), poll request status:
http
GET https://api.inflowpay.ai/v1/requests/{requestId}
X-API-Key: <INFLOW_API_KEY>Returns the current . Poll every few seconds until is no longer .
ApprovalResponsestatusPENDINGFor full transaction details after approval:
http
GET https://api.inflowpay.ai/v1/transactions/{transactionId}Where comes from the approved .
transactionIdApprovalResponse.transactionId如果无法使用Webhook监听器(本地开发、批量任务、简单脚本),可轮询请求状态:
http
GET https://api.inflowpay.ai/v1/requests/{requestId}
X-API-Key: <INFLOW_API_KEY>返回当前的。每隔几秒轮询一次,直到不再是。
ApprovalResponsestatusPENDING授权完成后,如需完整交易详情:
http
GET https://api.inflowpay.ai/v1/transactions/{transactionId}其中来自已授权的。
transactionIdApprovalResponse.transactionIdStep 7: Policies (Enable 0-Click Headless Payments)
步骤7:策略(实现一键式无界面支付)
Policies are pre-approved spending rules. When a payment request includes a and the request is within the policy's limits, it auto-approves immediately — no consumer interaction needed.
HEADLESSpolicyIdUse policies for:
- Autonomous AI agents that need to make purchases without per-transaction approval
- Recurring payments (subscriptions, automated top-ups)
- High-frequency low-value transactions
Direct creation (seller-initiated):
http
POST https://api.inflowpay.ai/v1/policies
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"type": "PAYMENT",
"action": "APPROVE",
"currency": "USDC",
"budget": 1000,
"threshold": 100,
"period": "MONTHLY",
"expires": "2026-12-31T00:00:00.000Z"
}Consumer-initiated request (the consumer must approve the policy via their device):
http
POST https://api.inflowpay.ai/v1/requests/policy
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"userId": "<consumer-uuid>",
"display": "FULL",
"userDetails": ["EMAIL"]
}This returns an — same flow as login/payment. Consumer approves via SDK or mobile, and the policy becomes active.
ApprovalResponsePolicy fields:
- —
action,APPROVE,DECLINEREVIEW - —
period,DAILY,MONTHLY,YEARLYONCE - — total allowance for the period
budget - — per-transaction maximum
threshold - — current usage (read-only on
spent)PolicyResponse
CRUD:
http
GET /v1/policies
GET /v1/policies/{policyId}
POST /v1/policies
PUT /v1/policies/{policyId}
DELETE /v1/policies/{policyId}/deleteAttach a policy to a payment:
json
{
"userId": "<consumer-uuid>",
"amount": 50,
"currency": "USDC",
"display": "HEADLESS",
"userDetails": ["EMAIL"],
"policyId": "<policy-uuid>"
}If the request is within budget and threshold, the response will already show .
status: APPROVED策略是预批准的消费规则。当支付请求包含且请求在策略限制范围内时,会立即自动批准——无需消费者交互。
HEADLESSpolicyId策略适用场景:
- 自主AI Agent无需每次交易都经过授权即可完成购买
- recurring支付(订阅、自动充值)
- 高频小额交易
直接创建(卖家发起):
http
POST https://api.inflowpay.ai/v1/policies
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"type": "PAYMENT",
"action": "APPROVE",
"currency": "USDC",
"budget": 1000,
"threshold": 100,
"period": "MONTHLY",
"expires": "2026-12-31T00:00:00.000Z"
}消费者发起请求(消费者需通过设备批准策略):
http
POST https://api.inflowpay.ai/v1/requests/policy
X-API-Key: <INFLOW_API_KEY>
Content-Type: application/json
{
"userId": "<消费者UUID>",
"display": "FULL",
"userDetails": ["EMAIL"]
}返回——与登录/支付流程一致。消费者通过SDK或手机完成授权后,策略生效。
ApprovalResponse策略字段:
- ——
action、APPROVE、DECLINEREVIEW - ——
period、DAILY、MONTHLY、YEARLYONCE - ——周期内总限额
budget - ——单笔交易最大限额
threshold - ——当前已使用额度(
spent中为只读字段)PolicyResponse
CRUD操作:
http
GET /v1/policies
GET /v1/policies/{policyId}
POST /v1/policies
PUT /v1/policies/{policyId}
DELETE /v1/policies/{policyId}/delete将策略附加到支付请求:
json
{
"userId": "<消费者UUID>",
"amount": 50,
"currency": "USDC",
"display": "HEADLESS",
"userDetails": ["EMAIL"],
"policyId": "<策略UUID>"
}如果请求在预算和限额范围内,响应会直接显示。
status: APPROVEDStep 8: Wallet Read Operations
步骤8:钱包查询操作
Read-only access to the seller's wallet state. Useful for dashboards, reconciliation, and balance checks.
http
GET /v1/balances — all currency balances
GET /v1/balances/{currency} — single currency balance
GET /v1/transactions — paginated transaction history
GET /v1/transactions/{id} — single transaction
GET /v1/users/self — current authenticated userAll return JSON. See for full schemas.
references/api-reference.md只读访问卖家钱包状态。适用于仪表盘、对账和余额检查。
http
GET /v1/balances — 所有币种余额
GET /v1/balances/{currency} — 单个币种余额
GET /v1/transactions — 分页交易历史
GET /v1/transactions/{id} — 单个交易详情
GET /v1/users/self — 当前认证用户信息所有接口返回JSON。完整Schema请查阅。
references/api-reference.mdVerification
验证
Run a smoke test to confirm everything works. Adapt the commands to whatever the project uses (npm scripts, curl, http file, etc.):
- API key auth — call with the configured
GET /v1/users/self. Should return the authenticated user. If 401, the key is wrong.X-API-Key - User search — call with a known email. Confirm 200 +
POST /v1/users/search, or 404 if the user doesn't exist.userId - Payment request — initiate a small test payment to the known . Confirm the response contains a
userIdandrequestId.status: PENDING - Polling (if implemented) — call and confirm the status updates as the consumer interacts.
GET /v1/requests/{requestId} - Webhook (if implemented) — once a real event is delivered, check the handler's logs to confirm: signature verified, payload parsed, handler logic executed, HTTP 200 returned. (You can also use to inspect past events and
GET /v1/eventsto replay one.)POST /v1/events/{eventId}/resend
If the user is in production, also recommend:
- A persistent idempotency store for s (DB or Redis)
eventId - Logging all webhook events for audit
- A dead-letter queue for failed webhook processing
运行冒烟测试确认所有功能正常。根据项目使用的工具(npm脚本、curl、http文件等)调整命令:
- API密钥认证——使用配置的调用
X-API-Key。应返回认证用户信息。如果返回401,说明密钥错误。GET /v1/users/self - 用户搜索——使用已知邮箱调用。确认返回200 +
POST /v1/users/search,或用户不存在时返回404。userId - 支付请求——向已知发起小额测试支付。确认响应包含
userId且requestId。status: PENDING - 轮询(如果已实现)——调用,确认状态随消费者操作更新。
GET /v1/requests/{requestId} - Webhook(如果已实现)——收到真实事件后,检查处理器日志,确认:签名验证通过、payload解析成功、处理器逻辑执行、返回HTTP 200。(也可使用查看历史事件,使用
GET /v1/events重放事件。)POST /v1/events/{eventId}/resend
如果用户处于生产环境,还建议:
- 为配置持久化幂等性存储(数据库或Redis)
eventId - 记录所有Webhook事件用于审计
- 为Webhook处理失败配置死信队列
Agentic User Setup (No Existing Account)
Agent用户设置(无现有账户)
If the user does NOT have an existing InFlow account, create an agentic (programmatic) user. This is a one-time setup and does NOT require existing authentication.
http
POST https://api.inflowpay.ai/v1/users/agentic
Content-Type: application/json
{
"locale": "EN_US",
"timezone": "US/Pacific"
}Returns:
json
{
"userId": "<uuid>",
"privateKey": "<your-api-key>",
"locale": "EN_US",
"timezone": "US/Pacific",
"created": "...",
"updated": "..."
}The is what goes in the env var. Store it securely — it cannot be retrieved again.
privateKeyINFLOW_API_KEY如果用户没有InFlow账户,可创建Agent(程序化)用户。这是一次性设置,无需现有认证。
http
POST https://api.inflowpay.ai/v1/users/agentic
Content-Type: application/json
{
"locale": "EN_US",
"timezone": "US/Pacific"
}返回:
json
{
"userId": "<UUID>",
"privateKey": "<你的API密钥>",
"locale": "EN_US",
"timezone": "US/Pacific",
"created": "...",
"updated": "..."
}privateKeyINFLOW_API_KEYIdempotency
幂等性
Before each step, check if the work is already done. Skip steps that are complete:
- If is already in
INFLOW_API_KEY/.env, skip env setup.env.example - If a webhook handler with HMAC verification already exists for InFlow paths, skip the webhook scenario
- If is already loaded somewhere in the frontend, skip the SDK script tag
inflow.js - If there's an existing helper module that wraps calls (look for
api.inflowpay.aiusage orINFLOW_API_KEYin source), reuse it instead of creating a new oneinflowpay.ai - If /
.envis not in.env.local, add it.gitignore
Always read the project before writing — don't duplicate existing logic.
执行每个步骤前,检查工作是否已完成。跳过已完成的步骤:
- 如果已在
INFLOW_API_KEY/.env中,跳过环境变量设置.env.example - 如果已存在针对InFlow路径的带HMAC验证的Webhook处理器,跳过Webhook场景
- 如果已在前端某处加载,跳过SDK脚本标签
inflow.js - 如果已有封装调用的辅助模块(查找
api.inflowpay.ai使用痕迹或源码中的INFLOW_API_KEY),复用该模块而非创建新模块inflowpay.ai - 如果/
.env未在.env.local中,添加进去.gitignore
编写代码前务必了解项目——不要重复已有逻辑。
Final Summary (After Implementation)
最终总结(实现后)
After implementing, give the user a clear summary in this format:
- Files created or modified — list each one with its purpose
- Env vars to set — name + what each is for + where to get the values
- What flows are now active — payment / login / register / webhook / polling / policies
- Manual steps the user must complete — be explicit about:
- Getting the API key (from dashboard or via )
POST /v1/users/agentic - Registering the webhook URL in the InFlow dashboard (no API for this — flag prominently if a webhook handler was created)
- Copying the webhook secret into
INFLOW_WEBHOOK_SECRET - Confirming the production SDK URL with InFlow before going live (sandbox URL is in code by default)
- Getting the API key (from dashboard or via
- Test commands — exact commands to verify each flow
- Next steps — what to do after the integration is wired up
Keep the summary terse. The user should be able to complete the integration after reading it.
完成实现后,向用户提供清晰的总结,格式如下:
- 创建或修改的文件——列出每个文件及其用途
- 需设置的环境变量——名称 + 用途 + 获取途径
- 已启用的流程——支付/登录/注册/Webhook/轮询/策略
- 用户必须手动完成的步骤——明确说明:
- 获取API密钥(从控制台或通过)
POST /v1/users/agentic - 在InFlow控制台中注册Webhook URL(无API支持此操作——如果创建了Webhook处理器,请突出提示)
- 将Webhook密钥复制到中
INFLOW_WEBHOOK_SECRET - 上线前与InFlow确认生产环境SDK URL(代码中默认使用沙箱URL)
- 获取API密钥(从控制台或通过
- 测试命令——验证每个流程的具体命令
- 下一步操作——集成完成后的后续建议
总结需简洁明了。用户阅读后应能完成集成收尾工作。