@0gfoundation/0g-pay-sdk

中文文档
0.4.0发布于 2026/09/30MITTypeScriptESM + CJS近 30 天下载 1928

0G Pay SDK - 0G支付集成的TypeScript/反应库

中文使用文档
文档目录50 节
  1. 安装
  2. 快速启动
  3. 加密/ 纸卡存款( TokenFlight)
  4. 花纹补充(信用卡-美元余额)
  5. 花纹再充电——分步教学
  6. 步骤1——获得会话符号
  7. 步骤 2 —— 将押金按钮以 Frede 配置
  8. 步骤3——处理回页
  9. 步骤4——(可选)独立的钩子
  10. 条纹客户端( Node.js / server- side)
  11. 导入
  12. 设置
  13. 交换会话令牌
  14. 获得平衡
  15. 创建退出会话
  16. 付票情况
  17. 列表上叠历史
  18. 获取使用
  19. 学分
  20. 完整的服务器侧流
  21. 合作伙伴 API
  22. 运动
  23. 程序
  24. API 参考
  25. getApiUrl(network?)
  26. getSessionUrl(network?)
  27. <OGPay>
  28. <StripeCheckoutForm>
  29. <StripeReturn>
  30. useStripeCheckout(config)
  31. useStripeReturn(sessionId, config)
  32. StripeClient
  33. StripeAuthError
  34. StripePollingTimeoutError
  35. 类型
  36. StripeConfig
  37. StripeClientConfig
  38. SessionInfo
  39. Balance
  40. Topup
  41. UsageItem
  42. CreditLot
  43. CheckoutSession
  44. CheckoutStatus
  45. EIP1193Provider
  46. 货币
  47. 钱包整合实例
  48. 开发者模式
  49. 自定义触发器
  50. 许可证

0G 付费 SDK

收押金和卡片付款的SDK 0G网络。 。 。 .

  • 通过 TokenFlight 加密/ 卡片 – 通过 TokenFlight 部件互换任何令牌或卡片支付
  • 花纹充电 ——直接通过Frede主机取出,使用0G付费后端填充美元余额
  • StripeClient ——无头节点.js / 服务器侧客户端:取出,平衡,使用,上架历史 ——不需要反应
  • /server 子路径 ——纯节点Js项目无反应捆绑(无) react编号 :react-dom 需要的对等分解)

安装

npm install @0gfoundation/0g-pay-sdk

同伴依赖关系 (只有反应项目)

npm install react react-dom

如果您只需要节点.js / 服务器侧客户端( NameStripeClient中,从 /server 子路径 - 不需要对应的对等分解 :

import { StripeClient } from '@0gfoundation/0g-pay-sdk/server';

快速启动

加密/ 纸卡存款( TokenFlight)

import { OGPay } from '@0gfoundation/0g-pay-sdk';

export function App() {
  const provider = window.ethereum; // any EIP-1193 provider

  return <OGPay provider={provider} />;
}

点击 交存 按钮打开一个与 TokenFlight 部件的模式,让用户将任何令牌互换或按卡支付.

花纹补充(信用卡-美元余额)

import { OGPay } from '@0gfoundation/0g-pay-sdk';

export function App() {
  const provider = window.ethereum;

  return (
    <OGPay
      provider={provider}
      stripe={{
        network: 'testnet',
        sessionToken: yourSessionToken,
        successUrl: `${window.location.origin}/topup/return`,
      }}
    />
  );
}

何时 stripe 模式收益a 纸牌(打字) 选项卡。 用户选择一个美元金额,点击付费,然后被重定向到 Strebe 主机的退出。 给钱后,史崔克会转回你的 successUrl。 。 。 .


花纹再充电——分步教学

花纹流有三部分:获得会话符,触发取出,并处理回页.

步骤1——获得会话符号

0G Pay后端需要为所有API调用一个会话符. 您将您的用户的 Privy 访问令牌交换为每届的付费会话令牌 .

import { getSessionUrl } from '@0gfoundation/0g-pay-sdk';

async function getPaySessionToken(privyAccessToken: string): Promise<string> {
  const res = await fetch(getSessionUrl('testnet'), {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ privy_token: privyAccessToken }),
  });
  if (!res.ok) throw new Error(`Session exchange failed: ${res.status}`);
  const { token } = await res.json();
  return token;
}

将令牌存储在组件状态或您的认证上下文中——在 JWT 到期前有效 .

步骤 2 —— 将押金按钮以 Frede 配置

将会话符号(以及可选的电子邮件)传入 stripe 道具 (英语). 这个 successUrl 必须在您的应用程序中指向一页 StripeReturn 构成部分(见步骤3).

import { OGPay } from '@0gfoundation/0g-pay-sdk';

export function TopupButton({ sessionToken, email }: { sessionToken: string; email?: string }) {
  const provider = window.ethereum;

  return (
    <OGPay
      provider={provider}
      stripe={{
        network: 'testnet',
        sessionToken,
        email,                                              // pre-fills Stripe checkout
        successUrl: `${window.location.origin}/topup/return`, // your return page
        cancelUrl: window.location.href,                    // where to go on cancel
      }}
    />
  );
}

当用户打开模式并单击 纸牌(打字) 选项卡,他们看到:

  • 预设金额 : 10美元 50美元 100美元 500美元
  • 自定义量输入
  • A 类 用名片支付 X 按钮

点击按钮呼叫 POST /v1/checkout 在 Pay 后端上,并将浏览器重定向到 Strede 托管的取出页面.

步骤3——处理回页

支付后, 条纹附件 ?session_id=cs_... 给您的 successUrl 并调整用户方向。 打开 StripeReturn 该页的构件——在确认付款(最多18秒)之前,它会投票后端,并显示结果.

// pages/topup/return.tsx (or your router equivalent)
import { StripeReturn } from '@0gfoundation/0g-pay-sdk';
import { useNavigate } from 'react-router-dom';

export function TopupReturnPage({ sessionToken }: { sessionToken: string }) {
  const navigate = useNavigate();
  const sessionId = new URLSearchParams(window.location.search).get('session_id') ?? '';

  if (!sessionId) return <p>Invalid return URL — missing session_id.</p>;

  return (
    <StripeReturn
      sessionId={sessionId}
      network="testnet"
      sessionToken={sessionToken}
      onConfirmed={(creditedUsd) => {
        console.log(`$${creditedUsd.toFixed(2)} added to balance`);
        navigate('/dashboard');
      }}
    />
  );
}

StripeReturn 使三个国家:

状态显示时间
Spinner + "确认你的付款..."正在投票
绿色"支付确认! 增加十.XX美元"后端确认 paid: true
安培"巴兰斯很快就会更新"18秒超时——付款可能成功,但后端缓慢

步骤4——(可选)独立的钩子

如果需要更严格的控制,直接使用钩子来代替预建的组件.

useStripeCheckout - 设立一个会议,在方案上调整方向:

import { useStripeCheckout } from '@0gfoundation/0g-pay-sdk';

function CustomTopupForm({ sessionToken }: { sessionToken: string }) {
  const { createSession, loading, error } = useStripeCheckout({ network: 'testnet', sessionToken });

  return (
    <>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button disabled={loading} onClick={() => createSession(50)}>
        {loading ? 'Redirecting…' : 'Pay $50 with Card'}
      </button>
    </>
  );
}

useStripeReturn 民意调查付款状况,并让自己的UI:

import { useStripeReturn } from '@0gfoundation/0g-pay-sdk';

function MyReturnPage({ sessionId, sessionToken }) {
  const { status, creditedMicros, availableMicrosAfter } = useStripeReturn(sessionId, {
    network: 'testnet',
    sessionToken,
  });

  if (status === 'loading') return <Spinner />;
  if (status === 'timeout') return <p>Payment received — balance updating soon.</p>;

  const creditedUsd = creditedMicros / 1_000_000;
  return <p>✓ ${creditedUsd.toFixed(2)} credited to your account.</p>;
}

条纹客户端( Node.js / server- side)

StripeClient 是无头客户端,没有反应或浏览器依赖性。 在 Node.js 服务器、无服务器功能、脚本或任何您需要程序驱动 0G Pay API 的环境中使用它.

要求数 节点.js 18+ (内部) fetch 财务报告和审定财务报表 AbortSignal.timeout) (中文(简体) ).

导入

// In a React project (react already installed):
import { StripeClient } from '@0gfoundation/0g-pay-sdk';

// In a pure Node.js project (no React needed):
import { StripeClient } from '@0gfoundation/0g-pay-sdk/server';

设置

const client = new StripeClient({
  network: 'testnet',       // 'testnet' | 'mainnet' — defaults to 'testnet'
  sessionToken: '...',      // session token from exchangeSession()
});

使用 baseUrl 指向您自己的代理或两个网络默认以外的主机:

const client = new StripeClient({
  baseUrl: 'https://your-pay-backend.example.com', // overrides network
  sessionToken: '...',
});

交换会话令牌

交换一个0G Pay会话符号的 Privy访问令牌. 回来的 token 用作 sessionToken 对于所有其他方法.

const { token, account_id } = await client.exchangeSession(privyAccessToken);

获得平衡

const { available_micros } = await client.getBalance();
const usd = available_micros / 1_000_000;

创建退出会话

const { session_id, url } = await client.createCheckoutSession({
  amountUsd: 50,                              // or use amountMicros: 50_000_000
  successUrl: 'https://yourapp.com/return',
  cancelUrl:  'https://yourapp.com/cancel',
  email: '[email protected]',                 // optional — pre-fills Stripe checkout
});
// url is the Stripe hosted checkout page — redirect the user there

amountUsd 财务报告和审定财务报表 amountMicros 它们是相互排斥的;必须提供一种.

付票情况

import { StripeClient, StripeAuthError, StripePollingTimeoutError } from '@0gfoundation/0g-pay-sdk/server';

try {
  const result = await client.pollCheckoutStatus(session_id, {
    maxAttempts: 6,    // default 6
    intervalMs: 3_000, // default 3000 ms
  });
  if (result.paid) {
    console.log(`Credited $${result.credited_micros / 1_000_000}`);
  } else {
    // All attempts returned paid: false — payment not yet confirmed.
    // This is a normal result for reconcile calls (e.g. page load checks).
  }
} catch (err) {
  if (err instanceof StripeAuthError) {
    // 401 or 403 — session token is invalid or expired. Refresh and retry.
    console.error(`Auth failed (${err.status}): ${err.message}`);
  } else if (err instanceof StripePollingTimeoutError) {
    // Never received a clean response in maxAttempts tries (network/server error).
    // err.cause holds the underlying error.
    console.warn(`No response after ${err.attempts} attempts`, err.cause);
  } else {
    throw err;
  }
}

投票行为:

  • 当 paid: true。 。 。 .
  • 如果所有尝试返回 paid: false,解决最后一个状态——而不是错误。 这使得单试调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和maxAttempts: 1工作自然进行.
  • 掷出 StripeAuthError 立即401/403——无复议.
  • 掷出 StripePollingTimeoutError (与 .cause)只有在完全没有收到干净的HTTP回复时.

列表上叠历史

const { topups, next_before } = await client.listTopups({ limit: 20 });
// paginate: pass next_before as `before` on the next call
const page2 = await client.listTopups({ limit: 20, before: next_before });

过 source 以支付来源过滤。 这在检查一个上架是否是用户的首个真实存款时很重要——后端可能会在任何Frede或上架上架之前还回信用类型行,导致天真"一行"检查误发:

// Only stripe and on-chain topups — correct for "is first topup" checks
const { topups } = await client.listTopups({ limit: 1, source: 'stripe,chain' });
const isFirstTopup = topups.length === 0;

获取使用

const { items, cursor } = await client.getUsage({ limit: 50 });
const page2 = await client.getUsage({ limit: 50, cursor });

学分

按支出顺序列出账户的信用区——促销奖金,抽奖和团队赠款(最快先到期).

一页一页,所以走到结尾,然后得出任何金钱数字:

const LIMIT = 500; // the backend's ceiling

const MAX_PAGES = 20; // a bound, not an expectation

// `extra` picks WHICH lots — leave it off to walk every lot, pass
// { state: 'granted' } for only the spendable ones. It deliberately cannot
// carry `limit` or `cursor`: the walk owns those, and a caller who lowered
// `limit` would make the completeness test below read a full page as short.
async function walkCreditLots(
  extra: Pick<GetCreditsParams, 'state'> = {},
): Promise<{ lots: CreditLot[]; complete: boolean }> {
  const lots: CreditLot[] = [];
  let cursor: string | undefined;

  for (let i = 0; i < MAX_PAGES; i++) {
    const page = await client
      .getCredits({ ...extra, limit: LIMIT, cursor })
      .catch(() => null);
    // Keep what arrived and call it partial. A 429 here is routine — this
    // endpoint allows 20 requests a minute across every reader of it — and
    // throwing would discard pages already in hand.
    if (!page) return { lots, complete: false };

    lots.push(...page.lots);

    // The server's cursor is the only way on. Where none comes back, a short
    // page is the end of the list and a full one is a list this deployment
    // cannot let you finish.
    if (!page.next_cursor) return { lots, complete: page.lots.length < LIMIT };
    cursor = page.next_cursor;
  }
  return { lots, complete: false };
}

const { lots, complete } = await walkCreditLots();
if (!complete) {
  // Do not derive a money figure from this. Show what you have and say it is partial.
}
for (const lot of lots) {
  // `source` is the category to branch on, `display` is the label to render.
  console.log(lot.source, lot.display, lot.state, lot.remaining_micros);
}

永远不要自己建立光标. 这很诱人——pay-v2的光标是 `${lot.expires_at}|${lot.lot_id}`,它将格式称为“通过惯例不公开”,以及 cursor 请求参数一直被转发。 不这样做的原因是你无法知道 什么样的部署 回答你, 其中之一不终止.

阅读 ?cursor 报告 next_cursor 运入 一个 pay-v2 承诺,所以一个pay-v2 年龄足以报告任何光标也忽略了你发送的光标,然后手拿回来 同页。一个合成光标的行走 。 (前面的代理在通过时也可以不报告光标) ?cursor 通到一个尊重它的后端,在这种情况下,一个已建成的光标会起作用。 反应中没有任何东西能区分两者,所以猜测购买一个主机上的工作行走和另一个无限回路. )

就是这样 complete 这是为。 在没有光标回来的地方,把清单当作是无法完成的,并这样说——一个部分清单承认它比一个悄悄错误的数字要好.

显示 state永远不要自生自灭——它是根据请求本身的时钟计算出来的,所以一个过期但又不流的多报告 'expired' 而不是看起来可以花钱:

// Credit this account can actually spend right now.
// `state: 'granted'` makes this one request on any real account; the filter stays
// regardless — see below.
const walked = await walkCreditLots({ state: 'granted' });
const spendable = walked.complete
  ? walked.lots
      .filter(lot => lot.state === 'granted' && lot.remaining_micros > 0)
      .reduce((sum, lot) => sum + lot.remaining_micros, 0)
  : null; // an incomplete list cannot produce this figure — say so, do not guess

state: 'granted' 不替换过滤器. 后端的参数的上游是 status = 'active' AND expires_at > now,这与权威的可支出金额不同,不包括 remaining_micros > 0排出但又不流出的地方 'granted' 什么都没有 保持滤波器也是使参数安全通过的原因:一个在它之前的部署会默默地忽略它,在设置滤波器时会花费多行而不是错误的数字.

只有在你想花很多钱的地方才能通过. 这是名单上的过滤器,所以任何需要死地的数字 都必须在没有它的情况下行走—— available_micros例如,计算未刷新过期的信用,显示用户被扣回的奖金需要被撤销的批次才能到达.

测试一个部署是否遵守了它只能回来"不". 问 'granted':如果大量到达另一个状态,参数被忽略了. 如果每一块都是 'granted'你从没有学到任何东西, 任何一种情况都一样。 所以永远不要从干净的结果中得出"光荣,一个请求就够了"的结论;保持行走.

为什么散步不是可选的. 很多人回来 expires_at ASC,则 'expired' 因此过期的地块在每一个活的地块之前排序. 'spent' 排出排出排出排出量后 排出量也往往很早. 'revoked' 已经 没有: 撤销是退款的补款或退款者收回信用,然后退出 expires_at 所以今天有12个多月的拨款 一小时后又取消 结束。因此,死地块不是一个可以停止扫描的前缀,最后一行的死地块则对列表是否完整没有任何说明.

一旦一个账户拥有比 limit掉出尾部的一行是 现场直播 信贷。 该页的信用金额少报了信用,通常的存款分出—— spendable_micros − Σ(credit)——多报存款数额完全相同。 这显示了给予的信用作为用户自己的钱。 在2026-09-22日的中场比赛中,付费v2击中了这个(2026-09-22)23号) (中文(简体) ).

一旦行走完成,这个减法是准确的,是获得存款数字的方法. Balance.spendable_micros 光靠自己是不能给你的,这是存款 加号 信用,这就是分拆存在的原因.

哪个主机尊重部署问题 不是SDK问题. 在撰写测试网主机报告时 next_cursor 荣誉 state;主网主机既不是. 所以不要用你刚刚读过的句子来编码 代码对应 complete 和反对 state 检查上面,步行 保持正确的任何.

分拆变更(后期,2026-09-20). CreditLot.status 已丢失; 使用 state旧字段是已过期的扫描簿记栏——读作 "active" 在信贷到期后一小时内,它无法从撤销中看出到期. state 都答对了.

完整的服务器侧流

import { StripeClient, StripeAuthError, StripePollingTimeoutError } from '@0gfoundation/0g-pay-sdk/server';

const PAY_URL = 'https://your-pay-backend.example.com';

// 1. Exchange Privy token once per user session
async function getClient(privyToken: string) {
  const client = new StripeClient({ baseUrl: PAY_URL, sessionToken: '' });
  const { token, account_id } = await client.exchangeSession(privyToken);
  return new StripeClient({ baseUrl: PAY_URL, sessionToken: token, accountId: account_id });
}

// 2. Create a checkout session and return the Stripe URL to the frontend
async function createTopup(privyToken: string, amountUsd: number, returnUrl: string) {
  const client = await getClient(privyToken);
  const { session_id, url } = await client.createCheckoutSession({
    amountUsd,
    successUrl: `${returnUrl}?session_id={CHECKOUT_SESSION_ID}`,
    cancelUrl: returnUrl,
  });
  return { session_id, url };
}

// 3. After Stripe redirects back, confirm payment and read updated balance
async function confirmTopup(privyToken: string, sessionId: string) {
  const client = await getClient(privyToken);
  try {
    const status = await client.pollCheckoutStatus(sessionId);
    const balance = await client.getBalance();
    return { status, balance };
  } catch (err) {
    if (err instanceof StripeAuthError) throw new Error('Session expired');
    if (err instanceof StripePollingTimeoutError) return { timedOut: true };
    throw err;
  }
}

合作伙伴 API

合伙人API是一组 公开, 只读 HTTP 端点 0G付费门户曝光. 不需要认证 – 用平面直接拨打 fetch。 。 。 .

使用 getApiUrl() 为每个网络解决正确的基址:

import { getApiUrl } from '@0gfoundation/0g-pay-sdk';

const BASE = getApiUrl('testnet'); // 'https://0g-pay-scan.vercel.app'

运动

竞选活动是获得资助的奖励池。 合作伙伴查询活动,向用户展示奖励.

列表活动

GET /api/partner/campaigns
const res = await fetch(`${BASE}/api/partner/campaigns`);
const data = await res.json(); // { campaigns: Campaign[] }
查询参数类型说明
statusstring按状态过滤 : active | closed | expired | pending_approval | withdrawn
limitnumber要返回的最大记录

获得竞选细节

GET /api/partner/campaigns/:id
const res = await fetch(`${BASE}/api/partner/campaigns/${campaignId}`);
const campaign = await res.json();

返回全部运动对象,包括其相关对象 lots (信贷分配).

每批报告 state (单位:千美元)granted | spent | expired | revoked),与 CreditLot.state从2026-09-20后端发布开始,它不再携带原始 status 栏中,它落后于现实达一小时,并显示已过期的信用为活动.

获得竞选记录

GET /api/partner/campaigns/:id/rollup
const res = await fetch(`${BASE}/api/partner/campaigns/${campaignId}/rollup`);
const stats = await res.json();

返回该运动的汇总统计数据——发放总数、剩余总数、用户数等.


程序

一个程序定义 奖励规则 如何在运动中计算和分配信贷。 方案披露其时间表、信用有效期和两级利率配置.

列表程序

GET /api/partner/programs
const res = await fetch(`${BASE}/api/partner/programs`);
const data = await res.json(); // { programs: Program[] }

样本反应——两个内置程序, topup-promo (携带) terms和 staking (没有):

{
  "programs": [
    {
      "program": "topup-promo",
      "running": true,
      "starts_at": "2026-09-11T00:00:00Z",
      "expires_at": "2026-09-26T23:59:59Z",
      "credit_duration_secs": 300000000,
      "live": true,
      "terms": {
        "first_topup": { "bonus_pct": 100, "cap_micros": 10000000000,
                         "definition": "bonus = the amount paid, capped at cap_micros" },
        "later_topups": { "bonus_pct": 33.333333333333336, "divisor": 3,
                          "definition": "bonus = the amount paid / divisor, rounded down" }
      }
    },
    { "program": "staking", "running": true, "starts_at": null, "expires_at": null,
      "credit_duration_secs": null, "live": true }
  ]
}
外地类型说明
programstring程序标识符 - 'topup-promo' 或者说 'staking'
runningboolean是否在门户中打开程序
starts_atstring | nullISO 8601 — 当程序窗口打开时
expires_atstring | nullISO 8601 — 当程序窗口关闭时
credit_duration_secsnumber | null每个发放的信用额持续多久, 以秒计
liveboolean发价是否正在发放信贷 —— 说 running 财务报告和审定财务报表 窗口内
termsobject | undefined晋级一级算术. 现为 topup-promo 仅限

使用 live 而不是比较 starts_at 编号 : expires_at 自己——服务器将自己的时钟折叠到这个领域,这样就不需要呼叫了,而且 running 单靠自己是不够的(一个窗口外的切换程序不发布任何东西).

每个条目下 terms 载:

外地类型说明
bonus_pctnumber百分比与 显示衍生的服务器与存款路径从同一规则中支付,所以没有表面广告显示分类账不同意的费率. 它没有圆形—— 100 一级,但 33.333333333333336 3分之一的分光器 绕来绕去展示
cap_microsnumber | undefined仅一级——奖金上限,以微美元计
divisornumber | undefined仅限后一级——上层除以此,下层
definitionstring语言规则, 服务器授权

问下一个账户的充值能赚多少钱

过 account_id 和回应收益 your_next_topup ——权威回答"这是这个用户的下个顶级吗". 更喜欢从上面排出第一:

GET /api/partner/programs?account_id=<32-hex account id>
const res = await fetch(`${BASE}/api/partner/programs?account_id=${accountId}`);
const { programs, your_next_topup } = await res.json();

// your_next_topup: { tier: 'first' | 'later' | '', terms?: Tier, as_of: string }
// `terms` is absent whenever `tier` is '' — nothing is on offer, so there is nothing to describe.
if (your_next_topup.tier === 'first' && your_next_topup.terms) {
  console.log(`First topup — ${Math.round(your_next_topup.terms.bonus_pct)}% back`);
}

tier 实值 '' 当无物可获的时候. as_of 是一个服务器时间戳 .

计算预期的入帐额

type Tier = { bonus_pct: number; cap_micros?: number; divisor?: number };
type Terms = { first_topup: Tier; later_topups: Tier };

// Dispatch on WHICH tier you are pricing, never on which fields happen to be present:
// `cap_micros` belongs to the first tier and `divisor` to later ones today, but a tier
// carrying both would silently take the wrong branch.
function computeBonus(amountMicros: number, terms: Terms, tier: 'first' | 'later'): number {
  if (tier === 'first') {
    // 100% of what was paid, capped. Deliberately not derived from bonus_pct: the backend
    // pins the first tier to the constant `ops.FirstTopupBonusPct` (0g-pay-v2,
    // internal/ops/promo.go) and writes the payout as "the whole paid amount" rather than
    // amount*pct/100, because at 100% the multiply is a no-op that risks overflow. The
    // percentage is published FROM that constant, so it is what you SAY, never what you
    // recompute from.
    return Math.min(amountMicros, terms.first_topup.cap_micros ?? amountMicros);
  }
  // Later tiers: integer division IS the rounding rule — floor, never round.
  const { divisor } = terms.later_topups;
  return divisor ? Math.floor(amountMicros / divisor) : 0;
}

const promo = programs.find(p => p.program === 'topup-promo');
// `terms` rides on topup-promo, but guard it: a program row with no configured
// arithmetic comes back without the key.
const bonus = promo?.live && promo.terms && your_next_topup?.tier
  ? computeBonus(50_000_000, promo.terms, your_next_topup.tier)
  : 0;

your_next_topup 从 ?account_id= 上方的请求表——一个没有回复的呼叫 programs 一个人.

显示 bonus_pct 中,但计算数字 cap_micros 编号 : divisor - 百分比是你们 说而不是存款路径支付。 在展示前绕一圈: 后一层是真正的分界,所以 33.333333333333336 电线上传来的东西.

确定用户是否有第一次补全

your_next_topup.tier 以上是直接答案,不需要推论。 如果你想检查历史 请打电话 StripeClient.listTopups 与 source: 'stripe,chain' 以排除服务记录的行,否则会产生虚假的"尚未补上":

const { topups } = await client.listTopups({ limit: 1, source: 'stripe,chain' });
const isFirstTopup = topups.length === 0;

每行还携带 bonus_micros 财务报告和审定财务报表 tier,所以过去的上注可以报告它实际得到的,而不重新发现它.


API 参考

getApiUrl(network?)

返回给定网络的基础 URL。 将此作为合作伙伴 API 调用的前缀 .

import { getApiUrl } from '@0gfoundation/0g-pay-sdk';

getApiUrl('testnet') // 'https://0g-pay-scan.vercel.app'
getApiUrl('mainnet') // 'https://pay.0g.ai'

两者均返回时不附带斜线- 附加路径为 /api/v2/...。 。 。 .

getSessionUrl(network?)

返回给定网络的会话交换端点.

getSessionUrl('testnet') // 'https://0g-pay-scan.vercel.app/api/v2/session'
getSessionUrl('mainnet') // 'https://pay.0g.ai/api/v2/session'

<OGPay>

Prop类型默认说明
providerEIP1193Provider—— 说要求. EIP-1193 钱包提供商(window.ethereum瓦格米,维姆,... )
childrenReactNode<button>Deposit</button>自定义触发元素
methodsstring[]['crypto', 'card']TokenFlight 部件中显示的支付方法
outputAmountstring—— 说预填部件中的输出量
lockFromTokenbooleanfalse将源代码锁定到本地代码
tradeTypestring'EXACT_INPUT'贸易类型传到 TokenFlight 部件
logoReactNode0G标志自定义模式页眉中的标志
onSuccess(data) => void—— 说当TokenFlight 交换成功时调用
onError(data) => void—— 说当 TokenFlight 互换失败时调用
mode'user' | 'developer''user''user':固定0G接收器. 'developer': 使用 recipientAddress
recipientAddressstring—— 说需要时间 mode="developer"。必须是有效的 0x… 后继地址
stripeStripeConfig—— 说提供后,增加a 纸牌(打字) 通过Frede 添加美元

<StripeCheckoutForm>

独立渲染取量器 UI —— 如果您想要在模式之外使用, 则有用 .

import { StripeCheckoutForm } from '@0gfoundation/0g-pay-sdk';

<StripeCheckoutForm
  config={{ network: 'testnet', sessionToken, email, successUrl, cancelUrl }}
/>
Prop类型说明
configStripeConfig要求. 条纹配置对象

<StripeReturn>

向后端出价,并让支付确认UI.

import { StripeReturn } from '@0gfoundation/0g-pay-sdk';

<StripeReturn
  sessionId={sessionId}
  network="testnet"
  sessionToken={sessionToken}
  onConfirmed={(creditedUsd) => { /* navigate away */ }}
/>
Prop类型说明
sessionIdstring要求. 这个 session_id frede 重定向的查询参数
networkNetwork'testnet' | 'mainnet' ——默认为 'testnet'
sessionTokenstring要求. 付费后端的会话令牌
onConfirmed(creditedUsd: number) => void后端确认支付时调用一次. 获得美元贷记额

useStripeCheckout(config)

const { createSession, loading, error } = useStripeCheckout(config: StripeConfig);
返回时类型说明
createSession(amountUsd: number) => Promise<void>创建条条形取出会话并重定向 window.location.href ưμ㼯A
loadingbooleantrue 当API呼叫正在飞行时
errorstring | null如果 API 呼叫失败, 错误消息 , null 否则

useStripeReturn(sessionId, config)

const { status, creditedMicros, availableMicrosAfter } = useStripeReturn(sessionId, {
  network: 'testnet',
  sessionToken,
});
返回时类型说明
status'loading' | 'confirmed' | 'timeout'目前投票情况
creditedMicrosnumber贷记额,以微额美元计(美元除以1,000,000美元)。 非零时 status === 'confirmed'
availableMicrosAfternumber入计后账户余额(以微美元计)

选票 GET /api/v2/topup/checkout/{sessionId} 最多 6次(6次) 与 3秒间隔 (18-秒上限). 立即停车 paid: true。 。 。 .

StripeClient

const client = new StripeClient(config: StripeClientConfig);
方法签署说明
exchangeSession(privyToken: string) => Promise<SessionInfo>交换一个0G Pay会话符号的 Privy访问令牌.
getBalance() => Promise<Balance>获取往来账户余额 .
createCheckoutSession(params: CreateCheckoutSessionParams) => Promise<CheckoutSession>创建条纹检查会话 。 回返 { session_id, url } -对 没有 转向.
pollCheckoutStatus(sessionId: string, options?: PollCheckoutStatusOptions) => Promise<CheckoutStatus>付款确认单 见下文投票行为.
listTopups(params?: ListTopupsParams) => Promise<ListTopupsResult>列出上层历史,最先更新.
getUsage(params?: GetUsageParams) => Promise<GetUsageResult>获取使用历史 .
getCredits(params?: GetCreditsParams) => Promise<GetCreditsResult>列出账户信用区一页. 页为 cursor 看到了吗 学分。 。 。 .

CreateCheckoutSessionParams

外地类型说明
amountUsdnumber数额(例如:. 50 页:1 相互排斥 amountMicros。 。 。 .
amountMicrosnumber数额(如:. 50_000_000 页:1 相互排斥 amountUsd。 。 。 .
successUrlstring支付后花纹会重新定位到这里. 这样做 没有 URL 编码 {CHECKOUT_SESSION_ID}。 。 。 .
cancelUrlstring取消时花旗重定向到这里 .
emailstring预填 Strepe 的电子邮件字段 .

PollCheckoutStatusOptions

外地类型默认说明
maxAttemptsnumber6最大的民调尝试.
intervalMsnumber3000几秒之间尝试.

ListTopupsParams

外地类型说明
limitnumber要返回的记录的最大数量 .
beforenumber相接光标 - 使用 next_before 从上页.
sourcestring由上出源过滤. 使用 'stripe,chain' 在检查第一版状态时排除信用类型行.

GetUsageParams

外地类型说明
limitnumber要返回的记录的最大数量 .
cursorstring相接光标 - 使用 cursor 从上页.

GetCreditsParams

外地类型说明
limitnumber每页很多 后端默认值 100, (中文(简体) ), 上限 500; 外部值 1..500 被忽略,你会得到 100。 。 。 .
cursorstring何处复会-回过前一页 next_cursor没有别的 光标被需要的部署忽略了.
state'granted'问后端 只为现在可花的地盘 在它之前的部署却默默地忽略了它 学分。 。 。 .

GetCreditsResult

外地类型说明
lotsCreditLot[]按开支顺序排列的一页expires_at ASC) (中文(简体) ).
next_cursorstring | null | undefined一个字符串意味着更多的可能遵循——设置在任意 满 页面,所以不是证据. null 或缺席意味着无法再到达一页:以简短的一页作为清单的末尾,加上 满 页面表示此部署无法页面, 您的列表是部分的 。 永远不要自己建立光标——看 学分。 。 。 .

列表为一页所页,一整页永远不能证明结尾. 从来没有从一个电话中得出一个钱的数字—— 学分 带路.

StripeAuthError

立即抛出 401编号 :403 答复——不重复.

class StripeAuthError extends Error {
  status: number;  // 401 or 403
}

被丢弃 : exchangeSession, (中文(简体) ), getBalance, (中文(简体) ), createCheckoutSession, (中文(简体) ), pollCheckoutStatus, (中文(简体) ), listTopups, (中文(简体) ), getUsage, (中文(简体) ), getCredits。 。 。 .

StripePollingTimeoutError

被丢弃 pollCheckoutStatus 何时 maxAttempts 已用尽, 并且从未收到过干净的 HTTP 响应( 即由于网络或服务器出错导致所有尝试失败 ) .

说明: 如果后端响应 paid: false 每一次尝试, pollCheckoutStatus 解决(返回最后状态)而不是投掷。 这让单一尝试调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调的调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和调和.

class StripePollingTimeoutError extends Error {
  sessionId: string;  // the session ID being polled
  attempts: number;   // how many attempts were made
  cause?: unknown;    // the underlying fetch/HTTP error from the last attempt
}

类型

import type {
  // React components & hooks
  StripeConfig,
  OGPayProps,
  EIP1193Provider,
  // StripeClient
  StripeClientConfig,
  CreateCheckoutSessionParams,
  PollCheckoutStatusOptions,
  ListTopupsParams,
  ListTopupsResult,
  GetUsageParams,
  GetUsageResult,
  GetCreditsParams,
  GetCreditsResult,
  SessionInfo,
  Balance,
  Topup,
  UsageItem,
  CreditLot,
  // Shared
  CheckoutSession,
  CheckoutStatus,
  Network,
} from '@0gfoundation/0g-pay-sdk';
// or from '@0gfoundation/0g-pay-sdk/server' for Node.js-only projects

StripeConfig

用于反应组件(OGPay, (中文(简体) ), StripeCheckoutForm)和钩.

interface StripeConfig {
  /** 'testnet' | 'mainnet' — defaults to 'testnet'. */
  network?: Network;
  /** Session token from POST getSessionUrl(network) */
  sessionToken: string;
  /** Optional email pre-filled in Stripe checkout */
  email?: string;
  /** URL Stripe redirects to after payment. Defaults to {origin}/topup/return */
  successUrl?: string;
  /** URL Stripe redirects to on cancel. Defaults to the current page */
  cancelUrl?: string;
}

StripeClientConfig

用于 StripeClient (节点.js / server-side).

interface StripeClientConfig {
  /** 'testnet' | 'mainnet' — defaults to 'testnet'. */
  network?: Network;
  /**
   * Explicit backend URL — takes precedence over `network`.
   * Use for self-hosted proxies or direct pay-backend access.
   */
  baseUrl?: string;
  /** Session token from exchangeSession() */
  sessionToken: string;
}

SessionInfo

interface SessionInfo {
  token: string;       // 0G Pay session token — use as sessionToken
  account_id: string;
}

Balance

interface Balance {
  available_micros: number;        // the account's TOTAL, every lot, whatever service it was granted for
  spendable_micros?: number | null; // what the CALLER may actually draw — gate on this one
  debt_micros: number;
  net_micros: number;
  serve: string | null;    // "allow" = good standing; other values = service paused
  display: { message?: string; [key: string]: unknown } | null;
  as_of: string | null;    // ISO 8601 timestamp of the balance snapshot
  stop_reason: string | null;
}

serve 财务报告和审定财务报表 stop_reason 来源于 spendable_micros,而不是从 available_microsA级 null spendable_micros 也就是说,答复中没有字段——将它视为不可信,而不是零.

Topup

interface Topup {
  id: number;               // pass as `before` to page past this row
  source: string;           // e.g. "stripe" | "chain"
  amount_micros: number;
  reversed_micros: number;
  status: 'credited' | 'partially_reversed' | 'reversed';
  created_at: string;       // ISO 8601
  reference: string;        // Stripe checkout session ID when source === "stripe"
  bonus_micros: number;             // what the promotion granted for this topup; 0 when nothing
  tier: 'first' | 'later' | null;   // null = the promotion had no view on it, NOT "later"
}

UsageItem

interface UsageItem {
  service: string;
  event_id: string;
  charge_batch_id: string;
  sku: string;
  unit: string;
  quantity_micros: number;
  rate_micros: number;
  amount_micros: number;
  occurred_at: string;      // ISO 8601
}

CreditLot

interface CreditLot {
  lot_id: string;
  remaining_micros: number;
  granted_micros: number;
  expires_at: string;                   // ISO 8601; never null
  service?: string | null;              // null = account-wide; otherwise the service it is scoped to
  source: 'promotion' | 'staking' | 'team';                // the category to branch on
  state: 'granted' | 'spent' | 'expired' | 'revoked';      // what became of it — the field to show
  display?: string | null;              // the label to render
  depth?: number;
  parent_lot_id?: string | null;
}
source手段
promotion顶级奖金
staking$iAI 悬赏
team竞选补助金
state手段
granted活跃和可花
spent排入至零( O)
expired过其过期时间——包括用户无法以两种方式花费的活性- unswept
revoked被取消:退款的补资,或退款的出资人

display 是标签:运动本身对团队信用的称呼,以及产品对两个内置程序(英语:"Top-up bonus", (中文(简体) ), "Staking reward") (中文(简体) ). 分会 source时 display ——不从一而出. 被吊销的奖励留在名单上,而不是消失,所以退款的用户会看到这种奖励——这就是为什么必须走这个观点的原因 无 state: 'granted',因为参数过滤 正是这些数量.

CheckoutSession

interface CheckoutSession {
  session_id: string; // Stripe checkout session ID (cs_...)
  url: string;        // Stripe hosted checkout URL
}

CheckoutStatus

interface CheckoutStatus {
  paid: boolean;
  credited_micros: number;       // Amount credited in micro-USD
  available_micros_after: number; // Balance after credit in micro-USD
  replayed: boolean;
}

EIP1193Provider

interface EIP1193Provider {
  request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;
}

兼容 window.ethereum瓦格玛的 useWalletClientViem的钱包客户端 以及EIP-1193供应商.


货币

所有内部使用量 微额数字 : 1 USD = 1,000,000 micros。 。 。 .

const usd    = micros / 1_000_000;
const micros = Math.round(usd * 1_000_000);

StripeClient.createCheckoutSession 接受其中之一 amountUsd (浮动美元)或 amountMicros (整数微分. 使用 amountMicros 当您的系统已经在整数分数或微数中工作以避免浮点转换时.


钱包整合实例

维基百科中的相关条目: 克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克

import { useWalletClient } from 'wagmi';
import { OGPay } from '@0gfoundation/0g-pay-sdk';

export function DepositButton() {
  const { data: walletClient } = useWalletClient();

  if (!walletClient) return null;

  return <OGPay provider={walletClient} />;
}

维姆

import { createWalletClient, custom } from 'viem';
import { OGPay } from '@0gfoundation/0g-pay-sdk';

const walletClient = createWalletClient({ transport: custom(window.ethereum) });

<OGPay provider={walletClient} />;

窗口。因此( MetaMask)

<OGPay provider={window.ethereum} />

开发者模式

设定 mode="developer" 供应 recipientAddress 将 TokenFlight 存款转到自己的地址,而不是 0G 收件人.

<OGPay
  provider={provider}
  mode="developer"
  recipientAddress="0xYourAddress"
/>

如果 mode="developer" 设置为无效 0x- 前置40个特征的六进制地址.


自定义触发器

传递任意元素为 children 作为触发器而不是默认 交存 按钮.

<OGPay provider={provider}>
  <button className="my-custom-btn">Top Up</button>
</OGPay>

<OGPay provider={provider}>
  <img src="/pay-icon.svg" alt="Pay" style={{ cursor: 'pointer' }} />
</OGPay>

许可证

麻省理工学院 0G 实验室

版本与发布记录

@0gfoundation/0g-pay-sdk 共发布 20 个版本,首次发布于 2026/04/27;过去 12 个月发布了 20 个版本。

版本发布日期距今
0.4.0latest2026/09/301 个月前
0.3.1-beta.12beta2026/09/251 个月前
0.3.1-beta.112026/09/241 个月前
0.3.1-beta.102026/09/241 个月前
0.3.1-beta.92026/09/241 个月前
0.3.1-beta.82026/09/211 个月前

关于 @0gfoundation/0g-pay-sdk 的常见问题

@0gfoundation/0g-pay-sdk 是什么?

0G Pay SDK - 0G支付集成的TypeScript/反应库

如何安装 @0gfoundation/0g-pay-sdk?

在项目目录运行 npm install @0gfoundation/0g-pay-sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=17.0.0)、react-dom(>=17.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@0gfoundation/0g-pay-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@0gfoundation/0g-pay-sdk 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@0gfoundation/0g-pay-sdk 可以商用吗?

@0gfoundation/0g-pay-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@0gfoundation/0g-pay-sdk 的下载量有多少?

根据 npm 官方下载统计,@0gfoundation/0g-pay-sdk 在 2026/10/04 – 2026/11/02 这 30 天内被下载 1,928 次,日均约 64 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@0gfoundation/0g-pay-sdk 还在维护吗?

最新版本 0.4.0 发布于 2026/09/30(1 个月前);至今共发布 20 个版本,其中过去 12 个月发布了 20 个;首次发布于 2026/04/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。